2

What are best practices in C++ when the copy/move constructors are called with the object itself?

For example:

#include <iostream>

using namespace std;

struct Foo{
    Foo( const Foo& foo ) { cout << foo.val << std::endl; };
    int val;
};

int main()
{
    Foo f = Foo(f);
    Foo g(g);
    Foo h{h};
    return 0;
}

This is all legal C++, though some compilers will warn you about it.

It is commonly advised that copy assignment operators check for self-assignment. But what about self-copy construction?

7
  • 6
    I cannot think of any time that it would be valid to copy to yourself during constructor. Foo f = Foo(f); invokes undefined behaviour, so it's meaningless anyway. Commented Jan 23, 2024 at 18:44
  • 1
    self assignment is more likely to happen accidentally. Say you have two references a and b and call a = b; then typically you wouldnt check whether a == b before. On the other hand Foo g(g); isnt happening that easily without being noticed Commented Jan 23, 2024 at 18:48
  • 1
    moreover the rationale they outline here isocpp.org/wiki/faq/assignment-operators#self-assignment-why doesnt apply to constructors. I mean there is a reason that Foo h{h}; is wrong, but its a different one Commented Jan 23, 2024 at 18:50
  • 2
    I am not sure how this can be answered. Asking for "best practice" is border line opinion based. The FAQ you link doesnt mention it anywhere and neither does the core guidelines afaik. Would that count as an answer? Commented Jan 23, 2024 at 18:54
  • 6
    "This is all legal C++" It isnt. You dont initialize val Commented Jan 23, 2024 at 18:55

1 Answer 1

1

A copy constructor for T creates a new object whose value is the same as that of an existing object (the argument for the copy constructor). If you pass the object to its own copy constructor, it doesn't have a value yet, so there's no value to copy.

This can therefore be viewed as calling the copy constructor "out of contract", a bit like if the argument to the copy constructor were an object that had already been destroyed. It's not a valid call, so you don't need to check for this case in the implementation—unlike the situation with a self-copy-assignment, where x = x; is a valid call, so you do need to make sure it works properly.

If it were common for users to accidentally pass an object to its own constructor, there might perhaps be value in having a purely defensive check in the implementation, but code like Foo g(g); is highly unlikely to be written.

It is even less likely that someone will attempt to move-construct an object from itself.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.