Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++0x, do non-static data member initializers override the implicit copy constructor?

According to N2628 related to c++0x, non-static data member initializers can be overridden by explicitly defined constructors, but it appears to be slightly nebulous about the implicitly defined copy constructor.

In particular, I've noticed that with Apple clang version 3.0, the behavior varies depending on whether the struct (or class) is a POD.

The following program returns output "1", which indicates that the copy-constructor is ignoring the right-hand-side, and instead substituting the new non-static data member initializer (in this example, the boolean true value for X::a).

#include <iostream>
#include <string>

struct X
{
    std::string string1;
    bool a = true;
};

int main(int argc, char *argv[])
{
    X x;
    x.a = false;
    X y(x);
    std::cout << y.a << std::endl;
}

However, confusingly, if you comment out string1:

    // std::string string1;  

then the behavior works as I expected (the output is "0"), presumably because there is no implicitly generated copy-constructor, and therefore the data is copied.

Does the C++0x specification really suggest that it is a good idea to allow the implicitly defined copy-constructor to not copy the contents of the right-hand side? Isn't that less useful and unintuitive? I find the non-static member initializer functionality to be quite convenient, but if this is the correct behavior, then I will explicitly avoid the feature due to its tricky and unintuitive behavior.

Please tell me I'm wrong?

UPDATE: This bug has been fixed in the Clang source repository. See this revision.

UPDATE: This bug appears fixed in Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn). This version of clang was distributed as part of Xcode 4.3 for Lion.

like image 565
Will Bradley Avatar asked Nov 21 '11 20:11

Will Bradley


People also ask

Where can a non-static reference member variable of a class be initialised?

Non-static data members may be initialized in one of two ways: 1) In the member initializer list of the constructor.

What is non-static data member in C++?

Non-static data members are the variables that are declared in a member specification of a class.

What is a non-static member object?

A non-static member function is a function that is declared in a member specification of a class without a static or friend specifier. ( see static member functions and friend declaration for the effect of those keywords)

Can we initialize static variable in constructor in C++?

There can not be multiple copies of same static variables for different objects. Also because of this reason static variables can not be initialized using constructors.


1 Answers

It isn't shadowy after all, see highlighted parts of the standards excerpt:

The section on defaulted copy/move constructors (§ 12.8) is a bit too lengthy to quote in it's entirety. The low-down is that non-static member fields with initializers are still simply copied by the defaulted copy/move constructor

§ 12.8:

-6. The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type:

  • if the member is an array, each element is direct-initialized with the corresponding subobject of x;
  • if a member m has rvalue reference type T&&, it is direct-initialized with static_cast(x.m);
  • otherwise, the base or member is direct-initialized with the corresponding base or member of x.
    Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor

This is the sample referred to:

struct A {
    int i = /* some integer expression with side effects */;
    A(int arg) : i(arg) { }
    // ...
};

The A(int) constructor will simply initialize i to the value of arg, and the side effects in i’s brace-or-equalinitializer will not take place. —end example ]


For completeness, the corresponding section on the defaulted default constructor:

§ 12.1

-6. A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement. If that user-written default constructor would be ill-formed, the program is ill-formed.
If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and its nonstatic data members shall have been implicitly defined. [ Note: An implicitly-declared default constructor has an exception-specification (15.4).
An explicitly-defaulted definition might have an implicit exception-specification, see 8.4. —end note ]

like image 83
sehe Avatar answered Sep 21 '22 01:09

sehe