tags:

views:

177

answers:

5
class Foo {

 public:
  Foo() { Foo(1)}
  Foo(int x, int y = 0):i(x) {}
 private:
  int i;
}

Can anybody give me some reasonas about can I do this? If not why?

+2  A: 

You cant do this. See section 10.3: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3. You can try to do it but doing so will construct a new temp object (not this) and be destroyed once control moves on.

What you can do however is to create a private function that initializes variables, one that your default constructor or a parameterized constructor can both call.

JonH
+9  A: 

Because the language specification doesn't allow it. Just the way the language is. Very annoying if you're used to Java or other languages that allow it. However, you get used to it after a while. All languages have their quirks, this is just one of C++'s. I'm sure the writers of the specs have their reasons.

Best way around this I've found is to make a common initialization function and have both constructors call that.

Something like this:

class Foo {
public:
    Foo() {initialize(1);}
    Foo(int nX) { initialize(nx); }

private:
    void initialize(int nx) { x=nx; }
    int x;
};
Daniel Bingham
This is the preferred method
Ramon Zarazua
It may be preferred but is inefficient since all the members are first default constructed, then overwritten by initialize.
Zan Lynx
Well, that becomes a question of optimization vs. minimizing code duplication. Depends on what's most important to the programmer doing the writing.
Daniel Bingham
+5  A: 

It's a language design choice.

A constructor is a one time (per-object) operation that creates a new object in uninitialized memory. Only one constructor can be called for an object, once it has completed the object's lifetime begins and no other constructor can be called or resumed on that object.

At the other end of its life a destructor can only (validly) be called once per object and as soon as the destructor is entered the object's lifetime is over.

A prinicipal reason for this is to make explicit when an object destructor will be run and what state it can expect the object to be in.

If a class constructor completes successfully then it's destructor will be called, otherwise the object's lifetime has never begun and the destructor will not be called. This guarantee can be important when an object acquires resources in its constructor that need to be released in its destructor. If the resource acquisition fails then the constructor will usually be made to fail; if the destructor ran anyway it might attempt to release an resource that had never been successfully acquired.

If you allow constructors to call each other it may not be clear if a calling or a called constructor is responsible for the resource. For example, if the calling constructor fails after the called constructor returns, should the destructor run? The called constructor may have acquired something that needs releasing or perhaps that was what caused the calling construtor to fail and the destructor shouldn't be called because the resource handle was never valid.

For simplicity of the destruction rules it is simpler if each object is created by a single constructor and - if created successfully - destroyed by a single destructor.

Note that in C++11 a constructor will be able delegate to a different constructor, but there are limitations that don't really relax the principal of one construction per object. (The prinicipal constructor can forward to a target constructor, but if it does it must not name anything else (base classes or members) in its initializer list. These will be initialized by the target constructor, once the target constructor returns the body of the prinicipal constructor will complete (further initialization). It is not possible to re-construct any bases or members, although it allows you to share constructor code between constuctors.)

Charles Bailey
Well this explains the view, but not really why the writers of the specifications choose to view it that way. Is there really any reason constructors can't delegate to each other? Why does the constructor have to be the point of object *creation* vs simply the point of object initialization that is called shortly after creation?
Daniel Bingham
@dbingham: TTBOMK, C++11 will allow forwarding to other constructors.
sbi
@dbingham: It allows you maximum control of the initial construction of base and member sub-objects, in many languages that allow you to call between constructors, the constructor is really a post-construction initialization routine, which can be useful but blurs the line between when an object has finished construction and it's lifetime has truly started and it's invariants are in place. This clarity can be quite important when initializing const members.
Charles Bailey
@Charles Bailey Hmmm... I suppose you're right. In Java, the language I'm primarily thinking of, construction and initialization is quite blurred. I guess there isn't that much more code duplication with the use of initialization functions and there is increased clarity. I might be convinced. Is there somewhere I can go to read a more detailed discussion of the reasoning behind the original choice?
Daniel Bingham
@dbingham: I've updated with more details about why I think it works the way it does - I may not be right, though. Herb Sutter has some excellent reading material in Exceptional C++ and gotw.ca about object lifetimes, RAII, etc. TBH, I've only ever missed delegating constructors once, 99.9% of the time I've wanted to share code between constructors it hasn't been specifically about intializing base classes and members so I've been able to break out the shared code into a non-virtual private function.
Charles Bailey
@Charles: Why wouldn't `struct X { X(int) {} X() : X(42) {} };` allow you just as much control over bas and sub-object construction?
sbi
@sbi: I don't think I'm saying it doesn't? (Although you need to be careful to specify how the allowed delegations interact with the defined object lifetimes, especially when you do something useful in a destructor.)
Charles Bailey
I was really answering the question of what does it give you to make the constructor the point of creation and not a post-creation initialization; the answer being that you get control over the initial creation. A consequence is that you do give the constructor special meaning and this can be important at the other end of the object's lifetime when you want to do something meaningful at the well defined point of the object's destruction. With Java none of this is as important as it's not a good idea to do anything meaningful at finalization; you've no guarantee when (if!) this happens.
Charles Bailey
+2  A: 

There is a really hideous hack I have seen used to call another ctor. It uses the placement new operation on the this pointer. erk

Like this:

Class::Class(int x) : x_(x) {}
Class::Class() {
    new (this) Class(0);
}
Class::Class(const Class &other) : x_(other.x_) {}
Class& operator=(const Class &other) {
    new (this) Class(other);
    return *this;
}

Note that I am not recommending this, and I don't know what horrible effects it might have on C++ structures like virtual base classes, etc. But I expect that there are some.

Zan Lynx
Unfortunately, this method shares all the disadvantages of the `initialize` routine since the members will *still* be default-constructed before the placement-new will occur. Add to that all the potential problems you cited …
Konrad Rudolph
A: 

Although as per standards vendors are free to implement data binding in their own ways, if we consider the most popular implementation: this pointer, we can see a reason why this can't be implemented.

Assume you have a class:

class A
{
    public:
    A(){}
    A(int a){}
} ;

With the this pointer implementation, this class would look something like:

class A
{
    public:
    A(A *this){}
    A(A *this,int a){}
} ;

Typically you would create objects like this:

A ob ;

Now when compiler sees this, it allocates memory for this and passes the address of this allocated memory block to the constructor of A which then constructs the object. It would try to do the same every time for each constructor called.

Now when you try calling a constructor within another constructor, instead of allocating new memory the compiler should pass the current objects this. Hence inconsistency!

Then another reason which i see is that even though you might want to call a constructor within another, u would still want a constructor to call default constructors for all the objects within the class. Now if one constructor were to call another, the default construction should happen for the first constructor and not for the subsequent one's. Implementing this behavior means that there would be several permutations which need to be handled. If not, then degraded performance as each constructor would default construct all the objects enclosed.

This is what i can think of as possible reasons for this behavior and do not have any standards to support.

hype
You are probably going too low-level with your analysis. In C++0x all of a sudden this is not going to be a problem! It's really up to the language specification to set the rules of the game.
UncleBens