Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to choose between constructors in main without writing a copy-constructor?

Real example is obviously much longer, but this sums up my problem:

class Object
{
 int mInt1,mInt2;
 Object::Object();
 Object::Object(int param1);
 Object::Object(int param1, int param2);
};
Object::Object(){}
Object::Object(int param1):mInt1(param1){}
Object::Object(int param1, int param2):mInt1(param1),mInt1(param2){}

Then in main:

if (type1){
  Object instance(param1);
}
else{
  Object instance(param1,param2);
}
// do stuff with instance

Whoops! That won't work, instance is out of scope for the program that follows.

Object instance;
if (type1){
  instance = Object(param1);
}
else{
  instance = Object(param1,param2);
}
// do stuff with instance

But now I run in to trouble because I didn't have a copy constructor defined. I'd really rather not write a copy-constructor because my actual class has dozens of members, many of which are non-basic types and might require even more work to copy.

Specifically, I am getting

main.cpp: error: use of deleted function ‘Object& Object::operator=(Object&&)’
         instance = Object(param1);
                  ^
note: ‘Object& Object::operator=(Object&&)’ is implicitly deleted because the default definition would be ill-formed:
like image 703
mmdanziger Avatar asked Mar 18 '14 12:03

mmdanziger


2 Answers

The universal way to deal with non-copyable objects is to throw it into a unique_ptr (or auto_ptr, depending on your compiler).

  std::unique_ptr<Object> instance;

  if (type1) {
    instance.reset(new Object(i));
  }
  else {
    instance.reset(new Object(i, j));
  }

Using raw pointers here really isn't safe because once you start having to deal with exceptions or any interesting code paths it becomes a chore to worry about leaks. Trust me, in 100% of cases, you will have less work and lines of code to deal with if you just drop it in a unique_ptr.


An optimal solution would be to redesign Object's constructors, because circumventing non-copyability may leave the object in an illegal state. In general, you want to preserve non-copyability if the compiler thinks it's necessary. We don't have the details here to flesh out such a solution however.

like image 81
QuestionC Avatar answered Oct 07 '22 15:10

QuestionC


If you do not want dynamically allocation then you can use an Initialize function:

class Object
{
 int mInt1,mInt2;
 Object::Object();
 Object::Initialize();
 Object::Initialize(int param1);
 Object::Initialize(int param1, int param2);
};
Object::Object(){Initialize();} //call the empty Initialize for nice coding...:)
Object::Initialize(){  }
Object::Initialize(int param1){ mInt1(param1); }
Object::Initialize(int param1, int param2){ mInt1(param1);mInt1(param2);}

Then you can use initialize to select the type.

Object instance;
if (type1){
  instance.Initialize(param1);
}
else{
  instance.Initialize(param1,param2);
}
like image 26
Lucian Avatar answered Oct 07 '22 15:10

Lucian