1

Why does the following not work when chaining constructors:

#include <iostream>
#include <vector>

class cls {
public:
    cls()           {cls(5);}       // want to resize v to 5
    cls(int n)      {v.resize(n);}
    std::vector<int> v;
};

int main(int argc, const char* argv[]) {
    cls x, y(5);
    std::cout << x.v.size() << std::endl;   // prints 0 <- expected 5
    std::cout << y.v.size();                // prints 5
    return 0;
}

Demo: http://ideone.com/30UBzS

I expected both objects to have a v of size 5. What's wrong?

Reason I want to do this is because writing separate cls() and cls(n) ctors would duplicate a lot of code.

mchen
  • 9,808
  • 17
  • 72
  • 125
  • is `{cls(5);} ` a typo?. It should be `v.resize(5)`; – stardust May 11 '13 at 17:48
  • That's my point, I wanted the 2nd constructor to handle it. It was hoping to avoid code repetition, as I've actually got much more than just a `v.resize` in my full code – mchen May 11 '13 at 17:50

4 Answers4

2

Calling cls(5); inside of the cls::cls() constructor is not doing what you think it is doing. It is creating a temporary variable using the second cls constructor which is destroyed at ;.

You can use C++11's delegating constructors to achieve what you want:

cls() : cls(5) { }

If you don't have a compiler that supports C++11, you can pull the common initialisation out into another function, and have both constructors call that:

class cls {
public:
    cls()           { init(5); }
    cls(int n)      { init(n); }
    std::vector<int> v;
private:
    void init(int n) { v.resize(n); }
};
user2093113
  • 3,230
  • 1
  • 14
  • 21
0

You should change

cls()  {cls(5);} 

to

cls()  {v.resize(5);} 

Otherwise you are creating new temporary cls in the constructor and ignoring it.


OR If you want to delegate the constructor (C++11) do it like this

cls() : cls(5)  {} 
//   ^^   ^
//        | use cls(int n)

delegated constructor are allowed only in the member initialization list of a constructor.

stardust
  • 5,918
  • 1
  • 18
  • 20
  • So I can't just call `cls(n)` like a normal function? What about if I want `cls() {dostuff(); cls(5); ...}`? – mchen May 11 '13 at 17:53
  • @MiloChen `cls(5)` creates a new class normally. Except when it is in the member initialization list of another constructor. – stardust May 11 '13 at 17:55
0

Here is what you need:

class cls
{
public:
       cls()
       :
       v( 5 ){}               // create v that contains 5 elements ( each initialized to 0 ) - note: this is NOT resizing

        explicit cls( const int size )
        :
        v( size ){}
private:       
        std::vector<int> v;
};

Of course, if you need resizing feature on the living object, you will need a 'resize' method already mentioned in this thread.

user1764961
  • 673
  • 7
  • 21
0

cal(5) creates a completely different object, in fact it's a temporary meaning the object will be destroyed at the end of its encapsulation expression. Or it might not be called at all due to compiler optimization.

But with that aside, the constructor call only affects the temporary and not the original object calling the constructor.

If your intention was to make the code shorter, you should create a member function that does this (assuming your compiler doesn't support C++11, in which case you could simply use the Delegating Constructor feature):

class cls
{
    void resize(int n)
    {
        v.resize(n);
    }

    public:
        cls()           { resize(5); }
        cls(int n)      { resize(n); }
        std::vector<int> v;
};
Community
  • 1
  • 1
David G
  • 94,763
  • 41
  • 167
  • 253