1

I have a Class called Request like this,

class Request {};

I store objects of this type in a global vector called,

std::vector<Request> requests;

I initialize the object using,

auto &request = requests.emplace_back();

Now, I attempt to delete the object using the reference provided by emplace_back like this,

requests.erase(std::remove(requests.begin(), requests.end(), request), requests.end());

It fails to compile and outputs following error,

sysroot/include/c++/v1\algorithm:2103:24: error: invalid operands to binary
      expression ('Request' and 'const Request')
            if (!(*__i == __value_))
                  ~~~~ ^  ~~~~~~~~

What should I do here to make it compile?

jeffbRTC
  • 1,941
  • 10
  • 29
  • 1
    Looks like you don't have an `==` operator defined for `Request`. Good wisdom on how to make one [can be found here](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – user4581301 May 17 '21 at 23:13
  • @user4581301 I thought it's done automatically?? I have came across answers that used exact same code to delete object by reference.. – jeffbRTC May 17 '21 at 23:18
  • undermany circumstances C++ will make `operator =` for you, but I'm not aware of any paths to an auto-generated `==` . [Spaceship operator](https://en.cppreference.com/w/cpp/language/default_comparisons) comes close, though. – user4581301 May 17 '21 at 23:21
  • @user4581301 https://stackoverflow.com/questions/21310646/stdvectoreraseitem-needs-assignment-operator-to-be-defined-for-item – jeffbRTC May 17 '21 at 23:21
  • That question is discussing `operator =`, not `operator ==`. – user4581301 May 17 '21 at 23:24
  • @user4581301 I know but the answer suggest unique_ptr as a workaround.. – jeffbRTC May 17 '21 at 23:25
  • That's because `erase` requires an assignment operator, `operator=`, to allow elements in the `vector` to be moved to new locations in the underlying data store. `std::unique_ptr` has an assignment operator. Here you need an equality comparison operator to satisfy `std::remove`. `Request` is trivial enough to create its own default assignment operator, but to get an equality compare you need to help the compiler along with `bool operator==(const Request&) const = default;` (after C++20) or `bool operator==(const Request& lhs, const Request& rhs){ /* do comparison */ }` (before c++20). – user4581301 May 17 '21 at 23:32
  • 1
    On a side note: `std::remove()` will iterate the entire `vector` comparing each element for equality, which is redundant in this case. Given a reference to an element in the `vector`, it is quite easy to calculate the element's index and then `erase()` just that element directly, without iterating or comparing elements at all, eg: `requests.erase(requests.begin() + (&request - &requests.front()));` Much more efficient. – Remy Lebeau May 18 '21 at 00:17
  • Just wondering: is `req.erase(remove(...), req.end())` safe? I remember that the evaluation order is unspecified. – 김선달 May 18 '21 at 00:43
  • Evaluation order is unspecified, but everything is A-OK because A) both will be complete and fully evaluated before `erase` is called and B) `remove` doesn't actually remove anything so the iterator returned by `end` is unaffected. – user4581301 May 18 '21 at 01:00
  • @RemyLebeau I like your way!! – jeffbRTC May 18 '21 at 02:37
  • @user4581301 Didn't know that `remove` doesn't actually remove anything. Thanks! – 김선달 May 18 '21 at 04:55

2 Answers2

2

In

requests.erase(std::remove(requests.begin(), requests.end(), request), requests.end());

The asker has been confused by answers to problems with std::erase and classes with no compiler-generated assignment operator. The problem here is not with std::erase and assignment operators, Request is, as presented at any rate, simple enough that the compiler will automatically generate an assignment operator for them. But keep an eye out for the Rule of Three and friends. Just because a default assignment operator can be generated doesn't mean the default behaviour is logically correct.

The asker's problem is with the std::remove portion of the line. std::remove needs a way to compare the Requests in requests to request to see which Requests match and need to be removed. std::remove uses the == operator to perform the comparison. The C++ compiler will not generate an equality operator for you because the odds of getting it wrong are far too high. For example, Which members are to be compared? All of them? One of them? First name and last name only? Student ID? Bank account number?

So we add a

bool operator==(const Request& lhs, const Request& rhs)
{ 
    return /* comparison logic*/;
}

to do the heavy lifting.

See What are the basic rules and idioms for operator overloading? for further details and general wisdom about operator overloading.

user4581301
  • 33,082
  • 7
  • 33
  • 54
0

The code compiles when defining operator==

class Request
{
public:
  bool operator==(const Request &other) const {return true;}
};

Best regards.

Patricio Loncomilla
  • 1,048
  • 3
  • 11