JUCE_DECLARE_NON_COPYABLE and move operators


#1

In many circumstances would it be better to have a JUCE_DECLARE_NON_COPYABLE_AND_NON_MOVABLE?

Discuss :slight_smile:

I started trying to formulate a view on this but it gave me a headache pretty quickly.


#2

Well, it depends what you want to happen with your objects. Most of the time when I put JUCE_DECLARE_NON_COPYABLE on something it’s because I only want one instance of it after creation and I usually don’t really mind where the data ends up, so moving it is fine.

Maybe there’s some demand for JUCE_DECLARE_NON_COPYABLE_AND_NON_MOVABLE, but I’ve not needed it myself.


#3

If I’m reading this sentence correctly:

Declaring any special member function except a default constructor, even as =default or =delete , will suppress the implicit declaration of a move constructor and move assignment operator.

…deleting the copy operations will effectively disable compiler-generated move operations, so making them as =delete would be for the sake of being explicit, not to change the compiler’s behavior.

I’m getting the leading edge of your headache now.


#4

If you put JUCE_DECLARE_NON_COPYABLE on a class then you won’t automatically get a compiler-generated move constructor or assignment operator. This is fine, because it doesn’t prevent you from moving, you just need to explicitly allow it. In most cases when you’ve put JUCE_DECLARE_NON_COPYABLE in place these are the kinds of things you’ll be worrying about anyway. In this respect JUCE_DECLARE_NON_COPYABLE acts exactly the same as JUCE_DECLARE_NON_COPYABLE_AND_NON_MOVEABLE would, but with an escape hatch.

It’s more dangerous when you allow copy construction or assignment, but only specify one of the move constructor/assignment pair. In this case it’s possible to end up unintentionally going via a copy when you attempt to move via the missing one.


#5

In 100% of the cases where I use JUCE_DECLARE_NON_COPYABLE in my projects, I want non-moveable as well. Usually the object is held by a shared/unique_ptr. I would find a JUCE_DECLARE_NON_COPYABLE_AND_NON_MOVABLE macro useful, and will probably start using something like that now.

Another case is when you capture this in a lambda, which is passed to other code. After the object is moved from, the lambda will get called with a this pointer still pointing to the moved-from instance.