Explicitly deleted move constructor - c++

Why this:
struct A
{
A(int) {
cout << "construct from int" << endl;
}
A(A&&) = delete;
A(const A &) {
cout << "copy constructor" << endl;
}
};
int main(){
A a = 0;
}
gives me an error:
error: use of deleted function ‘A::A(A&&)’
And why when I add such move constructor
A(A&&) {
cout << "move constructor" << endl;
}
it compiles fine, but programm's output is just
construct from int
So as far as I understand, compiler asks for constructor but doesn't use it. Why? This makes no sense to me.
P.S. I assume that
A a = 0;
is equvalent of
A a = A(0);
but why neither move constructor nor move assignment operator is called?

According to the C++ Standard (12.8 Copying and moving class objects)
31 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. In such cases, the implementation treats the
source and target of the omitted copy/move operation as simply two
different ways of referring to the same object, and the destruction of
that object occurs at the later of the times when the two objects
would have been destroyed without the optimization.122 This elision of
copy/move operations, called copy elision, is permitted in the
following circumstances (which may be combined to eliminate multiple
copies):
....
— 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
cv-unqualified type, the copy/move operation can be omitted by
constructing the temporary object directly into the target of the
omitted copy/move
and
30 A program is ill-formed if the copy/move constructor or the
copy/move assignment operator for an object is implicitly odr-used and
the special member function is not accessible (Clause 11). [ Note:
Copying/moving one object into another using the copy/move constructor
or the copy/move assignment operator does not change the layout or
size of either object. —end note ]

Related

Copy constructor implicitly called?

I have the following class with both a normal constructor and copy constructor defined.
#include <iostream>
class Bla
{
public:
Bla()
{
std::cout << "Normal Constructor Called\n";
}
Bla(const Bla& other)
{
std::cout << "Copy Constructor Called\n";
}
};
int main()
{
Bla a = Bla(); // prints Normal Constructor
}
In the main function, it prints the normal constructor as I expected and only the normal constructor. However, if I make the copy constructor a private member of the class, the compiler gives me the error
error: ‘Bla::Bla(const Bla&)’ is private within this context
From the looks of it, it looks like the copy constructor was called, but I do not see anything being printed from it. Is the copy constructor being implicitly called? What's going on here?
Before C++17, the copy operation might be elided but the copy constructor still needs to be present and accessible.
This is an optimization: even when it takes place and the copy/move (since C++11) constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed:
Since C++17 there's no such issue because of mandatory copy elision.
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

C++ optimization: avoid a copy operation

I have the following:
#include <iostream>
#include <utility>
class T {
public:
T() {std::cout << "Default constructor called" << std::endl;}
T(const T&) {std::cout << "Copy constructor called" << std::endl;}
};
static T s_t;
T foo() {
return s_t;
}
class A {
public:
A() = delete;
A(T t) : _t(t) {}
private:
T _t;
};
int main() {
std::cout << "Starting main" << std::endl;
A a(foo());
return 0;
}
When I compile it with the line:
g++ -std=c++17 -O3 test.cpp and run it, I get the following output
Default constructor called
Starting main
Copy constructor called
Copy constructor called
My question is: since the constructor of A is taking an r-value object of type T that is only used to initialize _t, is it possible for the compiler to avoid the second copy operation and just copy s_t directly into _t?
(I understand that I can potentially replace the second copy with a move by implementing a move constructor for T)
Your copy constructor has an observable side effect (output). The (almost) golden rule of C++ optimizations is the as-if rule: Observable side effects must not be changed. But one of the two exceptions from this rule is the elision of some copy operations, specified here:
http://eel.is/c++draft/class.copy.elision
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.
But this is only allowed in very specific circumstances:
This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object [...]
Your variable does not have automatic storage duration (i.e. it is not a local variable).
in a throw-expression, [...]
We are not a throw-expression.
in a coroutine [...]
We are not in a coroutine.
when the exception-declaration of an exception handler ([except]) declares an object of the same type (except for cv-qualification) as the exception object ([except.throw]) [...]
This is not the case either.
Neither the return of a global variable from a function, nor the use of a constructor parameter to initialize a member variable is covered here, so it would be illegal for any compiler to elide these copies in the code you show.
That said, if the compiler can prove that there are no side effects (which, in the case of most compilers, include system calls and memory allocations), it is of course free to elide the copy under the as-if rule, just like for all other optimizations.

When is the compiler allowed to optimize out the copy-constructor [duplicate]

This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 4 years ago.
Today I encountered something I don't really understand about copy constructor.
Consider the next code:
#include <iostream>
using namespace std;
class some_class {
public:
some_class() {
}
some_class(const some_class&) {
cout << "copy!" << endl;
}
some_class call() {
cout << "is called" << endl;
return *this; // <-- should call the copy constructor
}
};
some_class create() {
return some_class();
}
static some_class origin;
static some_class copy = origin; // <-- should call the copy constructor
int main(void)
{
return 0;
}
then the copy constructor is called when assigning origin to copy, which makes sense. However, if I change the declaration of copy into
static some_class copy = some_class();
it isn't called. Even when I am using the create() function, it does not call the copy constructor.
However, when changing it to
static some_class copy = some_class().call();
it does call the copy constructor.
Some research explained that the compiler is allowed to optimize the copy-constructor out, which sound like a good thing. Until the copy-constructor is non-default, as then it might, or might not do something obvious, right?
So when is it allowed for the compiler to optimize out the copy-constructor?
Since C++17, this kind of copy elision is guaranteed, the compiler is not just allowed, but required to omit the copy (or move) construction, even if the copy (or move) constructor has the observable side-effects.
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:
In the initialization of a variable, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the
variable type:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type:
T f() {
return T();
}
f(); // only one call to default constructor of T
Your code snippet matches these two cases exactly.
Before C++17, the compiler is not required, but allowed to omit the copy (or move) construction, even if the copy/move constructor has observable side-effects. Note that it's an optimization, even copy elision takes place the copy (or move) constructor still must be present and accessible.
On the other hand, call() doesn't match any conditions of copy elision; it's returning *this, which is neither a prvalue nor a object with automatic storage duration, copy construction is required and can't be omitted.

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

Temporary object destruction [duplicate]

This question already has answers here:
C++ unexpected behaviour (where are my temporaries!?)
(4 answers)
Closed 8 years ago.
Why isn't destructor for temporary object called after evaluating a full-expression:
#include <iostream>
struct A
{
int a;
A();
~A();
};
A::~A()
{
std::cout << "~A()" << std::endl;
}
A::A()
{
std::cout << "A()" << std::endl;
}
int main()
{
A b = A(); //Constructing of temporary object and applies copy-initalization
std::cout << "side effect" << std::endl;
//Destructor calling.
}
DEMO
Output:
A()
side effect
~A()
But 12.2/3 [class.temporary] says:
When an implementation introduces a temporary object of a class that
has a non-trivial constructor (12.1, 12.8), it shall ensure that a
constructor is called for the temporary object. Similarly, the
destructor shall be called for a temporary with a non-trivial
destructor (12.4). Temporary objects are destroyed as the last step in
evaluating the full-expression (1.9) that (lexically) contains the
point where they were created.
With your compiler and options the temporary is elided (optimized away), which is permitted.
Thus there is no temporary.
Thus there is no missing constructor and destructor call pair.
It's also well worth noting that the copy and move constructors are the only constructors where the compiler is allowed to assume that the constructor has no side effects, even when it knows better.
C++11 §12.8/31:
” When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. […]