icebp
icebp

Reputation: 1709

attempting to reference a deleted function when passing by reference with a const member

I'm clearly missing something out.

If I have:

class MyClass
{
public:
    const int something;

    MyClass(int Something) : something(something) {}
};

This will fail (attempting to reference a deleted function) because I have no copy constructor

std::vector<MyClass> myStuff;
std::sort(myStuff.begin(), myStuff.end(), 
    [](MyClass lhs, MyClass rhs) { 
        return lhs.something > rhs.something; });

So I should pass by reference. But I have the same problem even if the lambda becomes

[](const MyClass& lhs, const MyClass& rhs) { 
    return lhs.something > rhs.something; });

What's the reason behind this? The workaround is clear (don't have const member variables), but I want to know what I'm missing in the above example.

Upvotes: 3

Views: 1640

Answers (2)

NathanOliver
NathanOliver

Reputation: 180955

std::sort requires that the elements the iterators point to are MoveAssignable and MoveConstructible. You class is MoveConstructible but it is not MoveAssignable. The reason for that is you have a const member. You cannot assign to or move from a const member as that is a mutating operation. You can provide you own copy or move assignment operator to get around this or just make the member non const.

Upvotes: 3

Javier Mart&#237;n
Javier Mart&#237;n

Reputation: 2605

Your class has a const member, while you are asking std::sort to basically swap instances of your class around. Unlike a Java ArrayList, which contains handles (garbage-collected pointers) to the objects, C++ STL containers directly contain the objects themselves. Thus, you cannot swap the instances around because that would mean overwriting a const object. Your solution will have to be one of the following:

  • Sort a vector of pointers or references to the objects: you can use vector<MyClass*> or vector<reference_wrapper<MyClass>> if you have the instances elsewhere, or vector<unique_ptr<MyClass>> if the vector owns the instances.
  • Make the field non-const. Then your class will have a copy assignment operator (and a move ctor/op=, but with only that member it would be identical)
  • Provide a custom move/copy op= that uses const_cast to cast away the const-ness of the field. This is a bad idea, since the standard says it is undefined behaviour (i.e. the compiler and program may set your computer aflame if they want to) under certain cases. I don't remember the exact standardese, but you would have to be very careful not to fall in one of the jolly C++ undefined behaviour traps.

Upvotes: 3

Related Questions