Why Is This Code Trying to Call the Copy Constructor

Why is this code trying to call the copy constructor?

If you are using Visual Studio 2010 or 2012, be advised: the compiler does not automatically generate move constructors for you. That wasn't implemented. So you need to write them yourself.

C++ Why was the copy constructor called?

B(A aa) takes an A by value, so when you execute B b(a) the compiler calls the copy constructor A(const A& a) to generate the instance of A named aa in the explicit constructor for B.

The reason you can remove the copy constructor and have this still work is that the compiler will generate a copy constructor for you in cases where you have not also declared a move constructor.

Note: The compiler generated copy constructor is often not sufficient for complex classes, it performs a simple member wise copy, so for complex elements or dynamically allocated memory you should declare your own.

§ 15.8.1

If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly.
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy
constructor is defined as deleted; otherwise, it is defined as defaulted (11.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a user-declared destructor or assignment operator.

Why is the copy constructor called in this code after the assignment operator?

Because if you don't return a reference of the object it makes a copy.
As @M.M said about the final test() call, the copy does not appears because of the copy elision What are copy elision and return value optimization?

Why does my operator + overload call my copy constructor despite being passed by reference?

Creating a temporary point and changing its values will not call the copy constructor.

You are returning an object here, not a pointer or a reference to an object:

point operator + (const point& A, const point& B) { //Adds x1 to x2, y1 to y2

when you return from your function a new object is created from the one that you had inside your function and this is where the copy constructor gets called.

Why does calling std::move on a const object call the copy constructor when passed to another object?

The type of the result of calling std::move with a T const argument is T const&&, which cannot bind to a T&& parameter. The next best match is your copy constructor, which is deleted, hence the error.

Explicitly deleteing a function doesn't mean it is not available for overload resolution, but that if it is indeed the most viable candidate selected by overload resolution, then it's a compiler error.

The result makes sense because a move construction is an operation that steals resources from the source object, thus mutating it, so you shouldn't be able to do that to a const object simply by calling std::move.

c++ constructor and copy constructor

What you are seeing is called copy elision in a pre-C++17 compiler (try it out with C++17 on compiler explorer or wandbox with -std=c++17 vs. -std=c++14 flags). As of C++17 the compiler is required to eliminate many cases of copy and move constructors, and construct objects directly without any intermediate objects.

Unlike

A a { 10 };

the line

A a = 10;

means that a temporary object is constructed first, as if the code has:

A a = A(10);

Until C++17, the compiler was allowed to optimize this code, and construct a directly from 10 without the temporary object. Note that the emphasis is that it was allowed but not required to do this copy elision optimization. You have observed this allowed optimization.

The compiler had to compile or fail the code regardless of its decision to do copy elision. If the compiler could not call the copy constructor, like in your case, then it had to fail the compilation unconditionally, even if it decided to do copy elision. This changed with C++17, and the compiler is now required to make the copy elision optimization in this case. Since it is guaranteed to elide the copy constructor, no copy constructor is even required and the code can compile without an error.

Note the copy constructor without const:

A(A &other) { std::cout << " other " << std::endl; value = other.value; }

Without copy elision, this copy constructor can't be used for:

A a = A(10);

It can't be used because A(10) is a temporary object, and as such can be passed as an rvalue parameter to constructors and methods like

A(A && other);
foo(A && other);

or passed as a const lvalue reference parameter to constructors and methods like

A(const A& other);
bar(const A& other);

But it can't be passed as a regular mutable parameter (like in your code block 3).

With copy elision it does not even try to call the copy or the move constructor in these cases.

It still needs to call the copy constructor for

A b = a;

and it can do that with a mutable parameter, only because a is neither a temporary nor a const object. If you make a const then the code will fail to compile, when the copy constructor does not get a const (for C++17 and earlier):

const A a = 10;
A b = a;
// ^^ this will fail

Fun note: The following line will is guaranteed not to call the copy constructor even once with C++17:

A a = A(A(A(A(1))));

why isn't the copy constructor called

This is called as copy elision.

The compilers are allowed to do this optimization. Though it is not guaranteed by the standard any commercial compiler will perform this optimization whenever it can.


Standard Reference:

C++03 12.8.15:

[...] This elision of copy operations 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 to a class object with
    the same cv-unqualified type, the copy
    operation can be omitted by
    constructing the temporary object
    directly into the target of the
    omitted copy

You might use some compiler settings to disable this optimization, like in case of gcc, from the man page:

-fno-elide-constructor

The C++ standard allows an implementation to omit creating a temporary which is only used to initialize another object of the same type. Specifying this option disables that optimization, and
forces G++ to call the copy constructor in all cases.

However, using this makes your code non portable across different compilers.

What is referencing the copy constructor?

It's not just about the unnecessary copy and C++17, we know that

   Logger::Log foo("sample.log"); 

works fine but why this flags C2280 Error

   Logger::Log foo = Logger::Log::Log("sample.log");

the problem is in ofstream that is in the class, I got your code and I compiled it, I had a doubt about ofstream object, I deleted it, and it works fine also I made it a pointer also works fine, then I tried this code:

 std::ofstream s =  std::ofstream("sample.log", std::ios::out);
std::ofstream k;
k = s;

I got this error E1776 function "std::basic_ofstream<_Elem, _Traits>::operator=(const std::basic_ofstream<_Elem, _Traits> &) [with _Elem=char, _Traits=std::char_traits]" (declared at line 1080 of "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.25.28610\include\fstream") cannot be referenced -- it is a deleted function

which means ofstream prevent copy constructor and =operator to avoid the access to the same data (file) and this is the case in your code, when you call the copy constructor by this line

 Logger::Log foo = Logger::Log::Log("sample.log");

implicitly using the default copy constructor, it copies field by field using =operator for each object you have or a primitive type, and this is the case with ofstream that prevents the =operator then the compiler flags with calling a deleted function error--

to solve this you can declare ofstream pointer using raw pointers or smart ones and manage the memory or you can also create your move constructor version with your customization --which will delete the default copy constructor in your class also-- and try to avoid the access to the same data using different ofstreams.



Related Topics



Leave a reply



Submit