Copy constructor not calling - c++

When I read about copy initializing vs direct initializing here. copy constructor should call in copy initializing. why here copy constructor not calling?
#include <iostream>
using namespace std;
class A{};
class B{
public:
B(const A &a){cout << "B construct from A" << endl;}
B(const B &b){cout << "B copy constructor" << endl;}
};
int main(){
A a;
B b = a;
return 0;
}

This is Copy ElisionRef 1:.
Copy constructor calls while generating temporaries might be optimized by the compiler by creating objects inline and it is explicitly allowed by the C++ Standard.
This is nicely demonstrated in the standard with an example as well:
C++03 Standard 12.2 Temporary objects [class.temporary]
Para 2:
[Example:
class X {
// ...
public:
// ...
X(int);
X(const X&);
˜X();
};
X f(X);
void g()
{
X a(1);
X b = f(X(2));
a = f(a);
}
Here, an implementation might use a temporary in which to construct X(2) before passing it to f() using X’s copy-constructor; alternatively, X(2) might be constructed in the space used to hold the argument. Also, a temporary might be used to hold the result of f(X(2)) before copying it to `b usingX’s copyconstructor; alternatively,f()’s result might be constructed in b. On the other hand, the expressiona=f(a)requires a temporary for either the argument a or the result off(a)to avoid undesired aliasing ofa`. ]
Ref 1:
C++03 12.8 Copying class objects [class.copy]
Para 12:
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.....

Copy initialization is still subject to copy elision, and I'm guessing that's what's happening. Theoretically, a temporary B is constructed from a and the the copy constructor is used to create b from the temporary. In practice, the copy can be optimized out.
To test this, you can make the copy constructor private:
class B{
public:
B(const A &a){cout << "B construct from A" << endl;}
private:
B(const B &b){cout << "B copy constructor" << endl;}
};
and get a compilation error. This means the compiler expects the copy constructor to be accessible, but is not required to call it.
Copy elision is the only case where observed behavior can be altered.

Related

In which cases does cpp create a default copy constructor [duplicate]

This question already has answers here:
Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?
(3 answers)
Closed 2 months ago.
I am confused why this doesn't show an error because a copy of b is created but there is no copy constructor - struct A (line B c{b}; )
Did C++ create the copy constructor or is it something else in question? Thanks
#include <iostream>
using namespace std;
struct B{
int a = 0;
B(){cout << "3" << endl;}
~B(){cout << "5" << endl;}
};
struct A{
B b;
B c{b};
A(int a){cout << "4" << endl;}
A(){cout << "1" << endl;}
~A(){cout << "2" << endl;}
};
void foo(A y){
cout << "6" << endl;
}
void foo2(A& a){
cout << "7" << endl;
}
int main()
{
B a{};
A c{};
foo(2);
foo2(c);
return 0;
}`
From the documentation on copy constructors
If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class. This implicitly-declared copy constructor has the form T::T(const T&) if all of the following are true:
each direct and virtual base B of T has a copy constructor whose parameters are const B& or const volatile B&;
each non-static data member M of T of class type or array of class type has a copy constructor whose parameters are const M& or const volatile M&.
That is, C++ will create a copy constructor for you if it can (if each field can be copied) and if you haven't explicitly opted out or written one yourself.
You can opt out of a copy constructor (since C++11) with the delete keyword.
B(const B&) = delete;
This will forbid C++ from creating a copy constructor, even though you didn't define one.
In your case, B has no base classes, so the first bullet point does not apply. The only non-static member is of type int, which is not of class or array-of-class type and thus is trivial to copy.
It's very important to keep in mind that C++ will generate a copy constructor, even if it's not semantically correct to do so. For instance, if your class contains raw pointers, C++ is very likely to generate a copy constructor that does not do the right thing. That's because, for raw pointers, C++ doesn't understand Rule of Three/Five.
If your class owns a pointer, you should use std::unique_ptr (which has ownership semantics by default and will forbid copying, by the rules above). If your class shares ownership of a pointer, you should use std::shared_ptr, which will work correctly in the presence of a defaulted copy constructor. If your class borrows a pointer, you should consider using a reference type, and if that's not an option, you should clearly document your non-owning pointer and you should consider writing an explicit copy constructor if the default one doesn't satisfy Rule of Three/Five.
In your case, all you have is a (non-pointer) int, so the more complicated nuances don't come up. But if you keep learning C++, they will, so I recommend giving that Stack Overflow question a thorough read when you have the time.

Copy constructor call for temporary object

I have a following code:
#include <iostream>
using namespace std;
struct A
{
A() {}
A(const A&) { cout << "copy const" << endl; }
A(A&) { cout << "copy non const" << endl; }
};
A f(A a)
{
return a;
}
int main() {
A a1 = f(A());
}
The A(A&) copy constructor is called. Why A(const A&) is not called since I pass a temporary object?
When I comment out the A(const A&) copy constructor the program does not compile.
What you are seeing is a mix of copy elision and an actual copy being made. Since f takes a by value, It needs to copy A() into a. The compiler sees this copy really isn't needed, so it elides that and instead directly constructs a so you don't see any call. In the body of f when you return a;, it needs to copy a into the return value. Since a is a lvalue, A(A&) is a better match than A(const A&) so you see the call to the non const copy constructor. Then a1 needs to be initialized from f's return value. Again copy elision comes into play again and instead of seeing a copy it just directly puts the return value into a1's storage.
So, elide, non-const copy, elide, which leaves the output with just copy non const
You get an error when you remove A(const A&) because even though those copies were elided, C++ still required there to be copy constructor until C++17.
If you compile with gcc or clang and use -fno-elide-constructors you can actually see those copies. You can see that in this live example. Note that I used -std=c++11 to turn off C++17's guaranteed copy elision

I intend to call initializer_list constructor, and copy constructor is called beforehand if it exists: why?

The following type has three constructors. Note that one of them takes an initializer list of elements of that very same type.
struct Foo {
Foo() {
std::cout << "default ctor" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer_list<Foo>" << std::endl;
}
};
While initializing an object using an initializer_list, I am surprised to see the copy constructor is automatically called as many times as there are elements in the initializer_list. Afterwards, the initializer_list constructor is called:
int main()
{
Foo a; // default ctor
Foo b{a, a, a}; // copy ctor + copy ctor + copy ctor + initializer_list<Foo>
return 0;
}
What are the reasons/justifications behind that behavior? Note that if Foo had no copy constructor, the initialization Foo b{a, a, a} would apparently be perfectly possible (the initializer_list constructor would be the only one called).
Full code here: http://coliru.stacked-crooked.com/a/f6e28dbb66746aa2
What are the reasons/justifications behind that behavior?
The expression {a, a, a} (in your example) constructs a std::initializer_list<Foo>.
Each element of that array (yeah, you can intend an initializer list like a lightweight array) is construct as a copy of the object a.
Indeed, the copy constructor of that class is called three times in order to construct exactly three copies.
Note that if Foo had no copy constructor, the initialization Foo b{a, a, a} would apparently be perfectly possible (the initializer_list constructor would be the only one called).
That's no true. If Foo "has no copy constructor", the compiler will provide a default one. So in that case the copy constructor will be still called three times, as in the previous example.
You can prove it just deleting the default copy constructor.
From your example:
struct Bar {
// ...
Bar(const Bar&) = delete;
};
In this way, there is no copy constructor and code will not compile because of the error:
use of deleted function 'Bar::Bar(const Bar&)'
std::cout << "d : "; Bar d{c, c, c};
Indeed, it is not possible to construct the initializer list as usual.
Final Conclusions
There is no mystery in that.
You want to construct a "list" of three object. The compiler has to construct those object making copies from a.

Unusual behavior of copy ctor

#include<iostream>
#include<string>
using namespace std;
class B;
class A {
public:
A(const A&) { //copy ctor
cout << "Copy ctor A\n";
}
A() {} //default ctor
A(const B&) { //lets call this conversion ctor
cout << "B to A conversion ctor\n";
}
};
class B {
public:
};
int main()
{
B b;
A a = b;
}
The above code prints
B to A conversion ctor.
But as per what I have discovered after looking around for a while, it should print
B to A conversion ctor
Copy ctor A
As first a temporary object of type A is created by conversion ctor and then that object is copied into a wherein copy ctor gets called. Also, when copy ctor is made private, statement A a = b; generates this error:
‘A::A(const A&)’ is private
which is obvious as to copy the temporary object into a copy ctor must be visible.
So my question is why copy ctor is not being eventually called as evident from the output(please correct if am leading wrong somewhere here) even though it is required to be accessible?
A a = b;
This form is called copy-initialization. The applicable rule states that in this case a temporary A object will be constructed from the B instance and that temporary will then be used to direct-initialize a.
However, the compiler is allowed to elide the copy as it is not necessary. Even though the elision is allowed, the class still needs to be copyable for the form to be valid.
You can see the result without elision by passing -fno-elide-constructors to GCC or Clang.
why copy ctor is not being eventually called as evident from the output
According to the standard, an implementation is allowed to omit the copy/move construction in certain criteria. In this case, a temporary A(constructed from b, and will be copied to a) 's construction is omitted.
$12.8/31 Copying and moving class objects [class.copy]
When certain criteria are met, an implementation is allowed to omit
the copy/move construction of a class object, even if the constructor
selected for the copy/move operation and/or the destructor for the
object have side effects.
And
(31.3) — when a temporary class object that has not been bound to a
reference (12.2) would be copied/moved to a class object with the same
type (ignoring cv-qualification), the copy/move operation can be
omitted by constructing the temporary object directly into the target
of the omitted copy/move

When is aggregate initialisation valid in C++11?

Lets say we have the following code:
#include <iostream>
#include <string>
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
std::string s;
};
struct B
{
A a;
};
int main()
{
B{A()};
}
Here, I believe struct A is not an aggregate, as it has both non-trivial constructors and also a std::string member which I presume is not an aggregate. This presumably means that B is also not an aggregate.
Yet I can aggregate initialize B. In addition this can be done without either the copy nor move constructor being called (e.g. C++0x GCC 4.5.1 on ideone).
This behavior seems like a useful optimization, particularly for composing together large stack types that don't have cheap moves.
My question is: When is this sort of aggregate initialization valid under C++0x?
Edit + follow up question:
DeadMG below answered with the following:
That's not aggregate initialization at all, it's uniform initialization, which basically in this case means calling the constructor, and the no copy or move is probably done by RVO and NRVO.
Note that when I change B to the following:
struct B
{
A a;
B(const A& a_) : a(a_) {}
B(A&& a_) : a(std::move(a_)) {}
};
A move is performed.
So if this is just uniform initialization and just calling the constructor and doing nothing special, then how do I write a constructor that allows the move to be elided?
Or is GCC just not eliding the move here when it is valid to do so, and if so, is there a compiler and optimization setting that will elide the move?
According to the new standard, clause 8.5.1 (Aggretates), a sufficiently simple type (e.g. no user-defined constructors) qualifies as an aggregate. For such an aggregate Foo, writing Foo x{a, b, ... }; will construct the members from the list items.
Simple example:
struct A
{
std::unordered_map<int, int> a;
std::string b;
std::array<int,4> c;
MyClass d; // Only constructor is MyClass(int, int)
};
// Usage:
A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, MyClass(4,4)};
// Alternative:
A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, {4,4}};
The object x is constructed with all the relevant constructors executed in place. No maps or strings or MyClasses ever get copied or moved around. Note that both variants at at the bottom do the same thing. You can even make MyClass's copy and move constructors private if you like.
That's not aggregate initialization at all, it's uniform initialization, which basically in this case means calling the constructor, and the no copy or move is probably done by RVO and NRVO.