7

I am attempting to delete the copy constructor using the c++ type system to prevent copying an object.

struct DeleteCopyConstructor {
    DeleteCopyConstructor() {};
    DeleteCopyConstructor(DeleteCopyConstructor& op2) = delete;
    DeleteCopyConstructor(const DeleteCopyConstructor& op2) = delete;
};

DeleteCopyConstructor f() {
    DeleteCopyConstructor d;
    // initialize d...
    return d;
}

The error is:

error: use of deleted function ‘DeleteCopyConstructor::DeleteCopyConstructor(const DeleteCopyConstructor&)’

I've read about copy elision, but it appears to be a compiler optimization, so I don't think it applies. How can I return d without triggering copy construction?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
jcarpenter2
  • 5,312
  • 4
  • 22
  • 49

2 Answers2

2

In C++17 the compiler is guaranteed to elide the copy. However in all cases you still need to have a valid copy constructor.

So if you're just concerned about performance then you don't have to do anything. If you want to delete the copy constructor because the value logically shouldn't be copyable then there is no way to do it as far as I know. You'd have to return a std::unique_ptr<T> or take the value by reference and move into it that way. Edit: Or define a move constructor.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • `std::unique_ptr` is a very good suggestion (+1), but that's still too much indirection - one must suppose the goal is to initialize a value that exists on the stack of the caller. :) – jcarpenter2 Sep 25 '18 at 03:17
  • Yeah the only way I know to do that exactly is with placement new, but it will get very ugly. Move constructor is probably the next best option. – Timmmm Sep 25 '18 at 09:42
  • 1
    Because the compiler is now guaranteed to elide the copy or move, you can just declare a copy or move constructor and leave it unimplemented. This way, you can return by value, but legitimate copies/moves will generate a linker error. – yxrkt Mar 05 '19 at 02:30
  • 1
    Named return value optimization is not guaranteed in C++17. For the guaranteed copy elisions the copy/move operator also doesn't need to be accessible/usable since C++17. – user17732522 Mar 31 '22 at 05:27
-1

Copy elision, but it appears to be a compiler optimization, so I don't think it applies.

It does. Read more in Move or Named Return Value Optimization (NRVO)?

How can I return d without triggering copy construction?

Let the compiler take care of it.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 3
    Well, what I'm trying to do is lean on the type system to ensure correct code. I want copying an object to be a type error. Because copy elision is an optimization, and works in spite of language semantics saying the variable _should_ be copied, it would not suit my needs in this case. What I have taken to doing, is passing "out" parameters by ref, and "in" parameters by const ref - which is not perfect, but is working okay, and eliminates any need to return a value from a function without semantically copying it. – jcarpenter2 Sep 10 '17 at 21:31
  • I see @jcarpenter. Why you didn't accept my answer? You want me to modify it according your comment? I would say to keep it that way and leave your comment here. – gsamaras Sep 11 '17 at 06:14
  • I actually triggered a situation where NRVO didn't trigger although it is almost as simple as your above case. – CygnusX1 Aug 16 '18 at 15:57
  • 3
    @gsamaras because it does not answer the question. I want to lean on the type system here – jcarpenter2 Aug 17 '18 at 13:27