This question already has answers here:
Why copy constructor not invoked here
(2 answers)
Closed 8 years ago.
I have read some articles concerning this topic but still have problems to compile my own code.
I have class A:
class A
{
public:
List<int> data;
A(){}
A(A&){}
A& operator= (const A& a)
{
// copy the data from a to data
}
};
Class B will call class A:
class B
{
public:
A makeA()
{
A a;
return a;
}
A getA()
{
A a = makeA();
return a;
}
};
When I compile my code with g++ under Linux, I got:
no matching function for call to 'A::A(A)'.
It seems that the compiler has simply ignored the assignment operation. Can you help me out of this?
In order for this to compile, your copy constructor must take its parameter by const reference:
A(const A&){}
Adding const to your constructor signature fixes this problem (demo on ideone).
Since you are defining an assignment operator and a copy constructor, you should strongly consider adding a desctructor ~A() (see the Rule of Three).
The assignment operator is not used here.
A a = makeA();
This line is an initialization; it uses the copy constructor to copy the value returned by makeA into a. The compiler is complaining because A::A(A&) can't be used with a temporary; change it to the much more common form A(const A&) and things will be much better.
#Peter is right. The copy constructor A(A&){} wants to be A(const A&){}, instead. The reason is that A(A&){} tells the compiler to prepare to modify the A passed to the copy constructor, which does not really make sense, and certainly does not make sense in case the A you pass is a temporary.
Related
This question already has answers here:
What are the rules for automatic generation of move operations?
(2 answers)
How to find out which functions the compiler generated?
(3 answers)
Closed 2 months ago.
The following code doesn't compile -
struct A {
A() = default;
A(const A& other) = delete;
};
int main()
{
auto a = A();
auto u = std::make_unique<A>(std::move(a));
}
While the following does -
struct A {
A() = default;
A(const A& other) = delete;
A(A&& other) = default;
};
int main()
{
auto u = std::make_unique<A>(A());
}
The error I got is call to implicitly-deleted copy constructor.
Im using a blaze compiler for cpp-17.
Why does the first code segment not compile? It shouldn't use the copy contractor, just the move one.
Edit:
Adding A(A&& other) = default; solves the issue.
Does this mean that deleting the copy-contractor also deletes the move-contractor implicitly, and it needs to be added?
By deleting the copy constructor, you also implicitly delete the move constructor (A(A&& other)). If you want to use the first code segment, you must define your own custom move constructor (which will depend on the actual data of A).
Look at the concepts "rule of 5", "rule of 0" and related links (e.g. here) to get a grip on which constructors must be defined.
(by the way, the second code block does not compile on GCC or Clang, as pointed out in the comments. See godbolt. Edit: code in question was changed so this comment is no longer true.)
So if I've got a class and declare a copy assignment operator in it, obviously I want some special behavior when copying. I would expect the language to try to help me out by implicitly deleting the copy constructor until I explicitly bring it back, so as to avoid unintended different behavior when doing type instance = type() as opposed to already_existing_instance = type().
It's recommended anyway that you explicitly declare both copy constructor and copy assignment operator when trying to declare one of them, precisely because C++ doesn't delete the other and causes you a headache.
An example of where I find this annoying is when deleting the copy assignment operator. If I want to quickly make a class non-copyable, I would expect deleting the copy assignment operator does the trick, but I have to explicitly delete the copy constructor as well.
My question is why does the compiler do this? Who thought this was a good idea? All it does is create a needless obstacle for the programmer or am I missing something?
P.S. This behavior doesn't present itself when doing the same thing with move constructors/assignment operators, why make a distinction between copy and move in this case?
Them not being deleted is deprecated.
E.g. Clang 15 with -Wextra, given
struct A
{
A() {}
A(const A &) {}
};
int main()
{
A a, b;
a = b;
}
spits
<source>:4:5: warning: definition of implicit copy assignment operator for 'A' is deprecated because it has a user-provided copy constructor [-Wdeprecated-copy-with-user-provided-copy]
A(const A &) {}
^
<source>:10:7: note: in implicit copy assignment operator for 'A' first required here
a = b;
^
Similarly,
struct A
{
A() {}
A &operator=(const A &) {return *this;}
};
int main()
{
A a, b(a);
}
gives
<source>:4:8: warning: definition of implicit copy constructor for 'A' is deprecated because it has a user-provided copy assignment operator [-Wdeprecated-copy-with-user-provided-copy]
A &operator=(const A &) {return *this;}
^
<source>:9:10: note: in implicit copy constructor for 'A' first required here
A a, b(a);
^
This question already has answers here:
What's the exact semantics of deleted member functions in C++11?
(2 answers)
Closed 8 years ago.
After doing a bit of research, I see that C++11 has a defect with allocators that require the type to be movable/copyable. I'm sure that this is the cause of this problem, however I am confused about the behavior between deleted and not declared move semantics.
I have the following code which fails to compile on both MSVC12 and Clang:
#include <vector>
class Copyable
{
public:
Copyable() = default;
Copyable(Copyable const& other)
: m_int(other.m_int)
{}
Copyable& operator= (Copyable const& other)
{
m_int = other.m_int;
return *this;
}
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;
private:
int m_int = 100;
};
int main()
{
std::vector<Copyable> objects;
objects.push_back(Copyable{});
}
This fails to compile on MSVC with:
xmemory0(600): error C2280: 'Copyable::Copyable(Copyable &&)' : attempting to reference a deleted function
And on Clang (live sample):
new_allocator.h:120:23: error: call to deleted constructor of 'Copyable'
In both cases, when I remove the explicitly deleted move construct/assign methods, the code compiles. AFAIK when you declare copy assign/construct methods, the compiler does not implicitly declare the corresponding move members. So they should still be effectively deleted, right? Why does the code compile when I remove the explicit deletion of move construct/assign?
What is a good workaround for this C++11 defect in general? I do not want my objects to be movable (but they are copyable).
Deleting a function is not the same as not declaring it.
A deleted function is declared and participates in overload resolution, but if you attempt to call it an error is produced.
If you fail to declare your move constructor, the compiler will not create one as you created a copy constructor. Overload resolution on an rvalue will find your copy constructor, which is probably what you want.
What you said with your foo(foo&&)=delete was "if anyone tries to move construct this object, generate an error".
I can illustrate the difference here:
void do_stuff( int x ) { std::cout << x << "\n"; }
void do_stuff( double ) = delete;
void do_stuff2( int x ) { std::cout << x << "\n"; }
//void do_stuff2( double ) = delete;
int main() {
do_stuff(3); // works
//do_stuff(3.14); // fails to compile
do_stuff2(3); // works
do_stuff2(3.14); // works, calls do_stuff2(int)
}
the only part with your above problem that makes this a bit more confusing is that special member functions are automatically created or not based off slightly arcane rules.
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;
Unless you are an expert in move semantics (and I mean, really knowledgeable), never delete the special move members. It won't do what you want. If you review someone else's code that has done this, call it out. The explanation has to be really solid, and not "because I don't want the type to move."
Just don't do it.
The proper way to do what you want is to simply declare/define your copy members. The move members will be implicitly inhibited (not deleted, but actually not there). Just write C++98/03.
For more details, see this answer.
I have a simple class which contains an std::vector, and I would like to benefit from move semantics (not RVO) when returning the class by value.
I implemented the move constructor, copy constructor and copy assignment operators in the following way:
class A
{
public:
// MOVE-constructor.
A(A&& other) :
data(std::move(other.data))
{
}
// COPY-constructor.
A(const A& other) :
data(other.data)
{
}
// COPY-ASSIGNMENT operator.
A& operator= (const A& other);
{
if(this != &other)
{
data = other.data;
}
return *this;
}
private:
std::vector<int> data;
};
Are the above implementations correct?
And an other question: do I even have to implement any of these members, or are they auto-generated by the compiler? I know that the copy-constructor and the copy-assignment operator are generated by default, but can the compiler auto-generate the move constructor as well? (I compile this code both with MSVC and GCC.)
Thanks in advance for any suggestions. (I know that there already are some similar questions, but not for this exact scenario.)
They're all unnecessary for this class[*], since it would have implicit ones if you didn't declare any of them.
Your constructors are fine. So the following code ostensibly calls the move constructor:
A f() { return A(); }
A a = f(); // move construct (not copy construct) from the return value of f
In fact move-elision might kick in, in which case only the no-args constructor is actually called. I assume you plan to provide some constructors other than copy and move ;-)
Your copy assignment is fine, it differs from the implicit one only in that it has the self-assignment check, which the implicit one would not. I don't think we should have the argument whether a self-assignment check is worth it or not, it's not incorrect.
You haven't defined a move-assignment operator. Given that you defined the others, you should have done, but if you get rid of the rest it's implicit[*]. The move assignment operator (whether user-defined or implicit) is what ensures that the following code will move instead of copying:
A a;
a = f();
[*] On a completed C++11 implementation, of which so far none exist. You can check on a per-compiler basis whether this feature is implemented yet, and probably you'll end up with some horrible #define shenanigans until MSVC does.
For this exact scenario, You don't need to declare any move/copy/assignment functions. Compiler will generate correct defaults.
Edit: sorry I used "assignment constructor" instead of "assignment operator" in my original post. Fixed now.
It turns out that the copy constructor is called instead of the assignment operator in the following code. Anyone can tell me the reason behind this? Thank you.
class A
{
int i;
public:
A(int ii) { i = ii; }
A(const A& a) { i = a.i; i++; }
A& operator=(const A& a) { i = a.i; i--; }
};
int main(void)
{
A a(4);
A b = a;
return 0;
}
A a(4);
A b = a;
None of them is assignment1. Both are initialization.
First one is called direct-initialization, and second one is called copy-initialization.
The difference between them is that first one would work even if the copy-constructor is inaccessible (i.e its either private or protected), and second one would NOT work if the copy-constructor is inaccessible.
Even though the second one requires the copy-constructor to be accessible, that doesn't mean that the copy-constructor will necessarily be called. The compiler is allowed to optimize this, and so can elide the call to copy-constructor altogether. An accessible copy-constructor is needed for semantic validation.
See these topics :
Is there a difference in C++ between copy initialization and direct initialization?
When should you use direct initialization and when copy initialization?
c++ copy initialization & direct initialization, the weird case
1. And there is nothing such a thing called "assignment constructor".
operator= is not an "assignment constructor", it is an "assignment operator".
When you initialize a variable in its definition (as in A b = a), it is by definition equivalent to calling the copy constructor. ie, A b(a); and A b = a; are exactly equivalent.