In the next program, struct B
with deleted copy-constructor is thrown and caught by value:
struct B {
B() = default;
B(const B&) = delete;
};
int main() {
try {
throw B{};
}
catch( B ) {
}
}
Clang rejects the code with an expected error:
error: call to deleted constructor of 'B'
catch( B ) {
However GCC accepts the program finely, demo: https://gcc.godbolt.org/z/ed45YKKo5
Which compiler is right here?
In a return statement or a throw-expression, if the compiler cannot perform copy elision but the conditions for copy elision are met or would be met, except that the source is a function parameter, the compiler will attempt to use the move constructor even if the object is designated by an lvalue; see return statement ...
Sure, if you read/write a value via a reference, you read/write the original. But you can certainly copy a reference without copying the original object it refers to. Unless you mean if you copy a reference, whatever you do to the copy also applies to the original reference, not the original object being referred to.
Sometimes it's necessary to prohibit a copy constructor in a C++ class so that class becomes "non-copyable". Of course, operator= should be prohibited at the same time.
A trivial copy constructor is a constructor that creates a bytewise copy of the object representation of the argument, and performs no other action. Objects with trivial copy constructors can be copied by copying their object representations manually, e.g. with std::memmove.
C++ Class and Preventing Object Copy Jan 10, 20154 min read#c++#coding In some cases, an instance of a C++ class should not be copied at all. There are three ways to prevent such an object copy: keeping the copy constructor and assignment operator private, using a special non-copyable mixin, or deleting those special member functions.
There are times where an object should never be passed by copy but by reference or pointer. For instance, the class has a data member (like counter or mutex) which should not be duplicated. In this tip, we take a look at 2 techniques which declare the class to be non-copyable without resorting to using Boost's Noncopyable class.
A class that represents a wrapper stream of a file should not have its instance copied around. It will cause a confusion in the handling of the actual I/O system. In a similar spirit, if an instance holds a unique private object, copying the pointer does not make sense.
For instance, the class has a data member (like counter or mutex) which should not be duplicated. In this tip, we take a look at 2 techniques which declare the class to be non-copyable without resorting to using Boost's Noncopyable class. Delete the copy constructor and assignment operator. This works for C++11 and above.
Clang is correct. (Thanks for @NathanOliver's comments.)
[except.throw]/3
Throwing an exception copy-initializes ([dcl.init], [class.copy.ctor]) a temporary object, called the exception object. An lvalue denoting the temporary is used to initialize the variable declared in the matching handler ([except.handle]).
[except.throw]/5
When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]).
The exception object is considered as an lvalue, in the copy-initialization of the parameter of the catch clause, the copy constructor is selected. The copy operation might be elided as an optimization; but the copy constructor still has to be present and accessible.
I've reported this as gcc bug 103048.
BTW the copy-initialization of the exception object caused by throw B{};
is fine because of mandatory copy elision (since C++17).
In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With