D
D
Dmitry Kustersky2016-10-22 17:23:45
C++ / C#
Dmitry Kustersky, 2016-10-22 17:23:45

C++: Calling different constructors depending on user input?

There is a conditional code that constructs an object in one case with a string, in the other with a number (the bottom line is that it is of different types and, accordingly, calls different constructors):

Foo foo;
if (someFlag)
  foo = Foo("SomeString");
else 
  foo = Foo(42);

If I'm not mistaken, then this code will call at least one extra default constructor and one assignment operator. If the declaration of foo is included in the if-else block itself, then the problem is with the scope.
The question is how to make such a conditional call to the constructor correctly and without an overhead?
Only the variant with a pointer and foo = new Foo inside the if-else comes to mind, but then you need to remember to delete delete (unique_ptr is too verbose and I would like to avoid pointers altogether).
UPD: you can find options to get around the problem. The question is, first of all, whether it is possible to declare a custom class variable, but delay its initialization.
UPD2: maybe there is an option to expand the scope beyond the if-else block if you declare a variable there?
UPD3: Thank you all for the solutions, it was interesting to read.
The most adequate options at the moment look like copy-elision with a function that returns an object depending on the flag and a pointer. Although in my opinion both require extra gestures on the part of the programmer.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
M
MiiNiPaa, 2016-10-23
@dimykus

Variant with generator function:

inline Foo make_foo(bool someFlag)
{
    if (someflag)
        return  Foo("SomeString");
    else 
        return Foo(42);
}
//...
Foo = make_foo(someflag)

M
Mercury13, 2016-10-22
@Mercury13

1. Own code - make the init function

Foo foo;
if (someFlag)
  foo.init("SomeString");
  else foo.init(42);

2. Alien code - make a wrapper that will use placement new in init, and explicitly call the object destructor in the destructor.
class FooWrap {
public:
  FooWrap() : hasFoo(false) {}
  void init(int x) { new (fooPlace) Foo(x); hasFoo = true; }
  Foo& operator * () { return *reinterpret_cast<Foo*>(fooPlace); }
  Foo* operator -> () { return reinterpret_cast<Foo*>(fooPlace); }
  ~FooWrap() { if (hasFoo) (*this)->~Foo(); }
  // Да, и конструктор копирования и op= не забыть — оставлю как упражнение.
private:
  char fooPlace[sizeof(Foo)];
  bool hasFoo;
}

FooWrap foo;
if (someFlag)
  foo.init("SomeString");
  else foo.init(42);
foo->doFoo();

For greater reliability, it is worth specifying that FooWrap align as Foo - this is done through C ++ 11 or compiler extensions.

R
Rsa97, 2016-10-22
@Rsa97

Use pointer

Foo *foo;
if (someFlag)
  foo = new Foo("SomeString");
else 
  foo = new Foo(42);
...
delete foo;

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question