I'm trying to reset a full class with a virtual dtor.
Class Foo has lot's of data members, it would be easier to reset them all at once
class Foo : public QOject
{
public:
Foo() = default;
Foo(Foo&& rhs) = default;
Foo(Foo& rhs) = default;
Foo& operator=(const Foo& rhs) = default;
Foo& operator=(Foo&& rhs) = default;
private:
///lots of data members here
}
Since QOject has a virtual dtor no default constructors/operators are generated for Foo
When calling
mg_foo = Foo();
the compiler fails to generate a copy operator because QObject has virtual functions
I can't use pointers as well since at application startup I'm passing a raw address to QML
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("foo", &mg_foo);
If I use a pointer and change the address of mg_foo at runtime (with a brand new initialised class) my application crashes.
How would you handle such problem?
Check the QT documentation for the QObject class:
QObject has neither a copy constructor nor an assignment operator. This is by design. Actually, they are declared, but in a private section with the macro Q_DISABLE_COPY(). In fact, all Qt classes derived from QObject (direct or indirect) use this macro to declare their copy constructor and assignment operator to be private. The reasoning is found in the discussion on Identity vs Value on the Qt Object Model page.
The main consequence is that you should use pointers to QObject (or to your QObject subclass) where you might otherwise be tempted to use your QObject subclass as a value. For example, without a copy constructor, you can't use a subclass of QObject as the value to be stored in one of the container classes. You must store pointers.
So the compiler will fail to generate the copy and assignment operators no matter what you do. You might also want to note that the QObject's only constructor is QObject::QObject(QObject* parent=nullptr). Looking at the documentation, this means that every instance of Foo you create (with your compiler-generated default constructor) will be a top-level window.
As for what to do regarding "resetting" the class, you will have to be more specific about what you are looking for there.
If I understand the problem well, resetting the many data members should be very easy. Just put all the "many" data members to a private data class/struct.
class Foo : public QObject
{
public:
// ... public stuff
void reset();
private:
struct FooPrivate
{
// all the "many" data members with their default values
};
FooPrivate m_data;
};
void Foo::reset()
{
m_data = FooPrivate{}; // this resets the data
}
Yes the drawback is that you have to access all the members via m_data. But it is the price you pay for that you can reset the data in one line.
Btw. If I had too many data members in my class I would think twice about the design. It suggests that the class may have too much responsibility. And you know the rules: one class, one responsibility. Maybe you should change the overall design and split the class into two or more.
Related
Prior to C++11, I saw code like this:
class Car {
public:
Car() {}
private:
Car(const Car&);
Car& operator=(const Car&);
};
For C++11 (and later), I see code like this:
class Car {
public:
Car() {}
private:
Car(const Car&) = delete;
Car& operator=(const Car&) = delete;
};
Do they behave identically? If not, please explain.
Ref: https://ariya.io/2015/01/c-class-and-preventing-object-copy
They are similar in most respects, but differ in some others.
Consider the following external code trying to copy objects of the class:
int main() {
Car c;
Car other{c};
}
Both of these versions will cause the above code to fail. At this point, though, the developer would look at the interface to see why. With the delete version, it's obvious that Car was not meant to be copied. With the private version, (at least without a comment), it raises a doubt whether the copy constructor was perhaps placed in the private section by accident.
Now consider member code trying to copy objects of the class:
void Car::foo() {
Car c;
Car other{c};
}
The delete version fails like before. The private version is a link error. This raises an even greater doubt - it's not uncommon to forget to define a method that has been declared. Perhaps this is what's happened here? The delete version doesn't have this problem.
Edit Scott Meyers discusses this in Item 11 of Effective Modern C++ Prefer deleted functions to private undefined ones.
=delete will give more meaningful error messages. An error message about a deleted function tells you that it doesn't exist and no one can create an object with said constructor. Saying it is private doesn't give that information - it just says the caller cannot call it, not that no one can.
Also, a deleted constructor will not behave differently if called from within/outside the class (since private constructors can be called from within the class).
https://godbolt.org/g/06R9AQ
Note that the two snippets you posted give exactly the same error, that is something like:
'Car(const Car&)' is private within this context
This is because you defined the member methods as private in both cases.
If you want to appreciate the differences, you should rather have public deleted copy constructor and copy operator, that is:
class Car {
public:
Car() {}
// private: <-- this should not be here
Car(const Car&) = delete;
Car& operator=(const Car&) = delete;
};
This way, you will be informed that those member methods have been explicitly and intentionally deleted:
use of deleted function 'Car(const Car&)'
Setting them as private doesn't say explicitly I want to delete them.
As an example, it could have been done for you want to force the users of your class to use a factory method to create instances of that class.
Anyway, (no longer so) new features are not for free and using them in a way that is not the intended one won't give the expected benefits.
Car& operator=(const Car&) = delete; is expressing explicitly "copy assignment prohibited".
= delete; can also be used for any function as described on Bjarne's blog:
struct Z {
// ...
Z(long long); // can initialize with an long long
Z(long) = delete; // but not anything less
};
I thought in theory the answer to this question was yes.
However, in practice, my compiler (VS2010) does not seem to complain in the following situation: I have an abstract base class providing some common interface (yet having no data members) and various sub and subsubclasses derived from it.
class Base
{
public:
Base() {}
virtual ~Base() {}
virtual void interfaceFunction1() = 0;
virtual void interfaceFunction2() = 0;
private:
Base(const Base&); // all derived classes should be uncopyable
Base& operator=(const Base&);
// no data members
};
My compiler found it unproblematic to even implement full copy constructors in sub- or subsubclasses.
How can I make sure that every class derived from Base is uncopyable?
edit: If I understand well, this is exactly what Scott Meyers explained in item 6 of Effective C++ (3rd edition, 2005) with his idea of the class Uncopyable (only extended here to a full interface class). What is the difference that makes his idea work ? (I know that he inherits privately, but this should not pose a problem)
This should prevent the compiler from generating a copy constructor for derived classes which do not declare one explicitly. However, nothing prevents a derived class from explicitly declaring a copy constructor which will do something else than call the copy constructor of Base.
There is no way to make sure derived classes are instantiable but not copyable.
Rather than declaring the copy constructor/operator as private declare them as deleted. Declaring copy constructor/operator as private is not the best solution to making the derived classes non-copyable. If you want the base class to be completely non-copyable then declare the copy constructor/operator as deleted as copy can still take place inside the member functions of Base as private members are accessible to that class's functions. You can use the C++11 feature of delete:
Base(const Base&) = delete; // copy constructor
Base& operator=(const Base&) = delete; // copy-assignment operator
But declaring copy constructor/operator as private is also right as long as you're aware that copy can still take place inside the member functions of Base.
In C++11 and later there is the option to declare a constructor deleted.
struct X {
X( const X& ) = delete;
};
Now, anything derived from X that rely on the copy-constructor will not compile.
This is most useful when you want to avoid problems because the compiler auto-generates constructors...
I cannot understand the rationale behind the automatic addition of default ctors. In particular I find very awkward that every single time I just need to add an empty virtual destructor and nothing more, I loose the move stuffs, but adding them I loose the copy and default things, so I end up adding all this chunk of code:
virtual ~SomeClass(){} // you are the guilty!
//virtual ~SomeClass() = default // would be the same
SomeClass(SomeClass&&) = default; // no more auto-added
SomeClass& operator=(SomeClass&&) = default; // no more auto-added
SomeClass(const SomeClass&) = default; // but with the moves defined,
SomeClass& operator=(const SomeClass&) = default; // I'm now missing the copy
SomeClass(){} // and the default as well
I'm sure there is a reason for making my classes ugly and letting me desire an evil macro, I just would like to know it to feel more comfortable.
Take a look at this. It explains something called the rule of five, which is essentially what standard requires.
Generally, for most cases, compiler creates defaults for copy constructor, copy assignment, move assignment, and destructor. But, if a programmer defines any of these, then the compiler assumes the user has encapsulated something in this class that requires his/her special, let's say. destructor. Now that the programmer knows that he/she is going to need a destructor, the compiler will know that the programmer know what's going on and just not create the defaults for the rest (because, based on the assumption that the compiler makes, the default ones are going to be wrong, and can even result in undesired behavior).
The problem is that your class is trying to do two separate things: providing a polymorphic interface (hence the need for the virtual destructor) and managing concrete data members (hence the need for the copy/move operations). It's generally a good idea to give each class a single responsibility.
I'd move the virtual destructor, and any virtual function declarations, to an empty, abstract base class. Then any concrete class(es) deriving from that will be free to autogenerate all the needful things.
Example:
#include <iostream>
struct Movable {
Movable() {}
Movable(Movable&&m) {std::cout << "Moving\n";}
};
struct SomeInterface {
virtual ~SomeInterface() {}
// no data members, so no need for any other special member functions
};
struct SomeClass : SomeInterface {
Movable stuff;
// no user-declared special functions, so all are auto-generated
};
int main() {
SomeClass c;
SomeClass c2(std::move(c)); // uses the auto-generated move constructor
}
As the QObject documentation and many others explain, a QObject has an identity and thus hides its copy constructor and assignment operator.
However, I'm not deriving from QObject for its dynamic properties feature or the signals/slots feature. I only want reflection, or the ability to access Foo::staticMetaObject.
class Foo : public QObject {
Q_OBJECT
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
Q_DECLARE_METATYPE(Foo::Color)
I then can't copy Foo with:
Foo a;
Foo b;
a = b;
What's the best way to allow copy and assignment in this case? Do I absolutely need to write a copy constructor and assignment operator? What would they look like? Will reflection still work?
If you are only interested in having reflection for
the class name,
enums and flags (Q_ENUMS, Q_FLAGS),
class info (Q_CLASSINFO),
you can use Q_GADGET instead of Q_OBJECT:
class Foo {
Q_GADGET
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
which will declare and define Foo::staticMetaObject.
You can certainly implement both a copy constructor and a copy assignment operator in your derived class, but it's likely a sign of bad design. Take this example:
#include <iostream>
class Base {
public:
Base() {}
private:
Base(const Base& other) {
std::cout << "Base copy constructor invoked!" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {}
Derived(const Derived& other) {
std::cout << "Derived copy constructor invoked!" << std::endl;
}
};
int main(int argc, char** argv) {
Derived a;
Derived b = a;
return 0;
}
This will compile just fine. However, as expected, when you run the resulting program, all that is printed is Derived copy constructor invoked!. When the base class declares its copy constructor/copy assignment operator as private, that doesn't prevent derived classes from implementing their own versions. It simply prevents derived classes from calling the base class versions.
And therein lies the problem: it's always good practice to make sure you copy all parts of an object, so that you indeed have two distinct copies. Part of your object includes the data owned by the base class, so you should always make sure to invoke the base class's copy constructor/copy assignment operator to ensure that a full copy is made. But that data is by design non-copyable. Thus, it is impossible to copy all parts of the object.
It's up to you if you want to stick with this design. One important thing to ask yourself is, does your derived class really need to be copyable at all? If not, then there's nothing to worry about!
I don't know much about qt, but if the copy constructor is not allowed then there should be a reason for it (which is discussed in the link you posted). You can change your design not to have it.
Still if you insist then memcpy can be your last resort. I don't recommend it personally, because you have to take care about deep copying, vtable etc. which are not always trivial.
Why do people define a private copy constructor?
When is making the copy constructor and the assignment operator private a good design?
If there are no members in the class which are pointers or handles to a unique object (like file name), then wat other cases are there where private copy constructor is a good idea?
Same question apply for assignment operator. Given that majority of C++ revolves around copying of objects and passing by reference, are there any good designs which involve private copy constructor?
One use case is the singleton pattern where there can only be exactly one instance of a class. In this case, you need make your constructors and assignment operator= private so that there is no way of creating more than one object. The only way to create an object is via your GetInstance() function as shown below.
// An example of singleton pattern
class CMySingleton
{
public:
static CMySingleton& GetInstance()
{
static CMySingleton singleton;
return singleton;
}
// Other non-static member functions
private:
CMySingleton() {} // Private constructor
~CMySingleton() {}
CMySingleton(const CMySingleton&); // Prevent copy-construction
CMySingleton& operator=(const CMySingleton&); // Prevent assignment
};
int main(int argc, char* argv[])
{
// create a single instance of the class
CMySingleton &object = CMySingleton::GetInstance();
// compile fail due to private constructor
CMySingleton object1;
// compile fail due to private copy constructor
CMySingleton object2(object);
// compile fail due to private assignment operator
object1 = object;
// ..
return 0;
}
Some objects represent particular entities that can't or shouldn't be copied. For example, you may prevent copying of an object that represents the log file used by an application, corresponding to the expectation that a single log file will be used by all parts of the code. Use of an accidentally or inappropriately copied object could lead to out-of-order content appearing in the log, inaccurate records of current log size, multiple attempts (some failing) to "roll" to a new log filename or rename the existing one.
Another use is to enforce copying via a virtual function. As constructors can't be virtual, a common practice is to prevent direct access to the copy constructor and provide a virtual Base* clone() method that returns a copy of the actual run-time type to which a pointer points. This prevents the accidental slicing that Base b(derived) would exhibit.
Another example: a dead-simple smart pointer object that simply deletes the pointer it's given in the constructor: if it doesn't support reference counting or some other manner of handling multiple owners, and doesn't want to have risk awkward unintended std::auto_ptr style transfer of ownership, then simply hiding the copy constructor gives a great little smart pointer that's fast and efficient for the limited cases where it's usable. A compile time error about attempting to copy it would effectively ask the programmer "hey - if you really want to do that change me to a shared pointer, otherwise back off!".
A very bad example:
class Vehicle : { int wheels; Vehicle(int w) : wheels(w) {} }
class Car : public Vehicle { Engine * engine; public Car(Engine * e) : Vehicle(4), engine(e) }
...
Car c(new Engine());
Car c2(c); // Now both cars share the same engine!
Vehicle v;
v = c; // This doesn't even make any sense; all you have is a Vehicle with 4 wheels but no engine.
What does it mean to "copy" a car? (Is a car a car model, or an instance of a car? Does copying it preserve the vehicle registration?)
What does it mean to assign a vehicle to another one?
If the operations are meaningless (or merely unimplemented), the standard thing to do is to make the copy constructor and assignment operator private, causing a compile error if they're used instead of weird behaviour.
A common reason to make copy constructor and copy assignment private is to disable default implementation of these operations.
However, in C++ 0x there are special syntax =delete for such purpose.
So in C++ 0x making copy ctor private seems to be resrtricted to very exotic cases.
Copy ctors and assignments are rather syntactic sugar; so such a "private sugar" seems as symptom of greed :)
Even if the contents of the object aren't pointers or other references, preventing people from copying the object can still be useful. Perhaps the class contains a lot of data, and copying is too heavyweight of an operation.
The "virtual constructor idiom" is an important case where a private or protected copy constructor is needed. A problem arises in C++ where you are given the pointer to a base class, of an object that is actually inherited from this base class, and you want to make a copy of it. Calling the copy constructor would not call the copy constructor of the inheriting class, but actually call the copy constructor of the base class.
Observe:
class Base {
public:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = new Derived(*obj);
The code above would produce the output:
"Base copy constructor"
This is clearly not the behaviour the programmer wanted! The programmer was attempting to copy an object of type "Derived" but instead got back an object of type "Base"!!
The issue is rectified by using the aforementioned idiom. Observe the example written above, re-written to use this idiom:
class Base {
public:
virtual Base * clone () const = 0; //this will need to be implemented by derived class
protected:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
virtual Base * clone () const {
//call private copy constructor of class "Derived"
return static_cast<Base *>( new Derived(*this) );
}
//private copy constructor:
private:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = obj->clone();
The code above would produce the output:
"Base copy constructor"
"Derived copy constructor"
In other words, the object that was constructed in of desired type "Derived", and not of the type "Base"!
As you can see, in the Derived type, the copy constructor was intentionally made private, because it would be bad API design to give programmers to ability to accidentally try to call the copy constructor manually, rather than using the clever interface provided by clone(). Put another way, a directly callable public copy constructor available could cause programmers to make the mistake mentioned in part 1. In this case, best practise would have the copy constructor be hidden from view, and only indirectly accessible by using the method "clone()".
You might want to implement some of the methods of the class using a copy constructor, but not to expose it outside of the class. So then you make it private. Like any other method.