Remove an object in a std::vector by value - c++

I would like to remove an object from a stl vector if it is present.
class test
{
vector<Objects> myvector;
public:
test();
removeTest(Objects);
}
test::removeTest(Objects aObject)
{
myvector.erase(remove(myvector.begin(), myvector.end(), aTest),myvector.end());
}
However, whenever I try to compile this, I get the following error:
no match for 'operator=='
This only occurs if I use an iterator through a vector of objects of type 'Objects'. I can get it to work for the case of looking for an integer then removing this.
Anyone know why I am getting these errors? And am I using the correct method to remove an object from a stl vector of objects by value?

no match for 'operator=='
Error says it all. You need to provide an equality comparison for your Object class, std::remove can't otherwise know how to compare your objects to determine which ones need to be removed.
For example:
struct Object {
int i;
std::string s;
bool operator==(const Object& rhs) const {
return i == rhs.i && s == rhs.s;
}
};
It worked for integers because equality comparison between integers is built-in. Not so for user-defined types.
With that, this:
void test::removeTest(const Object& aObject)
// ^^^^ ^^^^^^^^^^^^^
{
myvector.erase(
remove(myvector.begin(), myvector.end(), aObject),
// ^^^^^^^
myvector.end()
);
}
Should do exactly what you want. Note that you were missing a return type for removeTest (I'm assuming you want void) and you should take the object you want to remove by reference-to-const to avoid the unnecessary copy.

Related

`auto` for the result of `std::set::find` in non-const context resolves to `std::_Rb_tree_const_iterator` in g++ (GCC) 7.3.0 with `-std=c++11` [duplicate]

I find the update operation on std::set tedious since there's no such an API on cppreference. So what I currently do is something like this:
//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);
Basically the iterator return by Set is a const_iterator and you can't change its value directly.
Is there a better way to do this? Or maybe I should override std::set by creating my own (which I don't know exactly how it works..)
set returns const_iterators (the standard says set<T>::iterator is const, and that set<T>::const_iterator and set<T>::iterator may in fact be the same type - see 23.2.4/6 in n3000.pdf) because it is an ordered container. If it returned a regular iterator, you'd be allowed to change the items value out from under the container, potentially altering the ordering.
Your solution is the idiomatic way to alter items in a set.
C++17 introduced extract, see Barry's answer.
If you're stuck with an older version, there are 2 ways to do this, in the easy case:
You can use mutable on the variable that are not part of the key
You can split your class in a Key Value pair (and use a std::map)
Now, the question is for the tricky case: what happens when the update actually modifies the key part of the object ? Your approach works, though I admit it's tedious.
In C++17 you can do better with extract(), thanks to P0083:
// remove element from the set, but without needing
// to copy it or deallocate it
auto node = Set.extract(iterator);
// make changes to the value in place
node.value() = 42;
// reinsert it into the set, but again without needing
// to copy or allocate
Set.insert(std::move(node));
This will avoid an extra copy of your type and an extra allocation/deallocation, and will also work with move-only types.
You can also extract by key. If the key is absent, this will return an empty node:
auto node = Set.extract(key);
if (node) // alternatively, !node.empty()
{
node.value() = 42;
Set.insert(std::move(node));
}
Update: Although the following is true as of now, the behavior is considered a defect and will be changed in the upcoming version of the standard. How very sad.
There are several points that make your question rather confusing.
Functions can return values, classes can't. std::set is a class, and therefore cannot return anything.
If you can call s.erase(iter), then iter is not a const_iterator. erase requires a non-const iterator.
All member functions of std::set that return an iterator return a non-const iterator as long as the set is non-const as well.
You are allowed to change the value of an element of a set as long as the update doesn't change the order of elements. The following code compiles and works just fine.
#include <set>
int main()
{
std::set<int> s;
s.insert(10);
s.insert(20);
std::set<int>::iterator iter = s.find(20);
// OK
*iter = 30;
// error, the following changes the order of elements
// *iter = 0;
}
If your update changes the order of elements, then you have to erase and reinsert.
You may want to use an std::map instead. Use the portion of Element that affects the ordering the key, and put all of Element as the value. There will be some minor data duplication, but you will have easier (and possibly faster) updates.
I encountered the very same issue in C++11, where indeed ::std::set<T>::iterator is constant and thus does not allow to change its contents, even if we know the transformation will not affect the < invariant. You can get around this by wrapping ::std::set into a mutable_set type or write a wrapper for the content:
template <typename T>
struct MutableWrapper {
mutable T data;
MutableWrapper(T const& data) : data(data) {}
MutableWrapper(T&& data) : data(data) {}
MutableWrapper const& operator=(T const& data) { this->data = data; }
operator T&() const { return data; }
T* operator->() const { return &data; }
friend bool operator<(MutableWrapper const& a, MutableWrapper const& b) {
return a.data < b.data;
}
friend bool operator==(MutableWrapper const& a, MutableWrapper const& b) {
return a.data == b.data;
}
friend bool operator!=(MutableWrapper const& a, MutableWrapper const& b) {
return a.data != b.data;
}
};
I find this much simpler and it works in 90% the cases without the user even noticing there to be something between the set and the actual type.
This is faster in some cases:
std::pair<std::set<int>::iterator, bool> result = Set.insert(value);
if (!result.second) {
Set.erase(result.first);
Set.insert(value);
}
If the value is usually not already in the std::set then this can have better performance.

How to return a private pointer to a list of pointers as const?

I have a pointer to a list of pointers, as a private variable. I also have a getter that returns the pointer to the list. I need to protect it from changes.
I couldn't find how to use reinterpret_cast or const_cast on this.
class typeA{
shared_ptr<list<shared_ptr<typeB>>> l;
public:
shared_ptr<list<shared_ptr<const typeB>>> getList(){return (l);};
};
The compiler returns:
error: could not convert ‘((typeA*)this)->typeA::x’ from ‘std::shared_ptr<std::__cxx11::list<std::shared_ptr<typeB> > >’ to ‘std::shared_ptr<std::__cxx11::list<std::shared_ptr<const typeB> > >’|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
It seems as const shared_ptr<list<shared_ptr<typeB>>> and shared_ptr<const list<shared_ptr<typeB>>> work fine.
Is it possible to do return l as a complete const, like:
const shared_ptr<const list<shared_ptr<const typeB>>>
or at least like:
shared_ptr<list<shared_ptr<const typeB>>>
?
References instead of pointers is not an option. To declare l as shared_ptr<list<shared_ptr<const typeB>>> also is not a wanted solution.
EDIT: no 'int' anymore.
It seems as it is not possible exactly what I wanted, but the suggested solutions are good. Yes, copying pointers is acceptable.
My bad i didn't put typeB immediately. I am aware of some advantages of references over pointers, but I hoped there is some similar solution.
You can create a new list of const int's from your original list and return that:
std::shared_ptr<std::list<std::shared_ptr<const int>>> getList(){
return std::make_shared<std::list<std::shared_ptr<const int>>>(l->begin(), l->end());
}
If you want to prevent people from making changes to the returned list, make it const too:
std::shared_ptr<const std::list<std::shared_ptr<const T>>> getList(){
return std::make_shared<const std::list<std::shared_ptr<const T>>>(l->cbegin(), l->cend());
}
The shared pointer returned by this function does not point to the original list but to the newly created list.
An alternative may be to provide iterators that, when dereferenced, returns const T& (where T is the type you actually store). That way there will be no need to copy the whole list every time you want to go though it. Example:
#include <iostream>
#include <list>
#include <memory>
struct example {
int data;
example(int x) : data(x) {}
};
template <class T>
class typeA {
std::shared_ptr<std::list<std::shared_ptr<T>>> l = std::make_shared<std::list<std::shared_ptr<T>>>();
public:
template< class... Args >
void add( Args&&... args ) {
l->emplace_back(std::make_shared<T>(std::forward<Args>(args)...));
}
// a very basic iterator that can be extended as needed
struct const_iterator {
using uiterator = typename std::list<std::shared_ptr<T>>::const_iterator;
uiterator lit;
const_iterator(uiterator init) : lit(init) {}
const_iterator& operator++() { ++lit; return *this; }
const T& operator*() const { return *(*lit).get(); }
bool operator!=(const const_iterator& rhs) const { return lit != rhs.lit; }
};
const_iterator cbegin() const noexcept { return const_iterator(l->cbegin()); }
const_iterator cend() const noexcept { return const_iterator(l->cend()); }
auto begin() const noexcept { return cbegin(); }
auto end() const noexcept { return cend(); }
};
int main() {
typeA<example> apa;
apa.add(10);
apa.add(20);
apa.add(30);
for(auto& a : apa) {
// a.data = 5; // error: assignment of member ‘example::data’ in read-only object
std::cout << a.data << "\n";
}
}
When you convert a pointer-to-nonconst to a pointer-to-const, you have two pointers. Furthermore, a list of pointers-to-nonconst is a completely different type from a list of pointers-to-const.
Thus, if you want to return a pointer to a list of pointers-to-const, what you must have is a list of pointers-to-const. But you don't have such list. You have a list of pointers-to-nonconst and those list types are not interconvertible.
Of course, you could transform your pointers-to-nonconst into a list of pointers-to-const, but you must understand that it is a separate list. A pointer to former type cannot point to the latter.
So, here is an example to transform the list (I didn't test, may contain typos or mistakes):
list<shared_ptr<const int>> const_copy_of_list;
std::transform(l->begin(), l->end(), std::back_inserter(const_copy_of_list),
[](auto& ptr) {
return static_pointer_cast<const int>(ptr);
});
// or more simply as shown by Ted:
list<shared_ptr<const int>> const_copy_of_list(l->begin(), l->end());
Since we have created a completely new list, which cannot be pointed by l, it makes little sense to return a pointer. Let us return the list itself. The caller can wrap the list in shared ownership if the need it, but don't have to when it is against their needs:
list<shared_ptr<const int>> getConstCopyList() {
// ... the transorm above
return const_copy_of_list;
}
Note that while the list is separate, the pointers inside still point to the same integers.
As a side note, please consider whether shared ownership of an int object makes sense for your program - I'm assuming it is a simplification for the example.
Also reconsider whether "References instead of pointers is not an option" is a sensible requirement.
You problem squarely lies at
but I do not want to mix references and pointers. It is easier and cleaner to have just pointers.
What you are finding here is that statement is wrong. A list<TypeB> can bind a const list<TypeB> & reference, and none of the list's members will allow any modification of the TypeB objects.
class typeA {
std::vector<typeB> l;
public:
const std::vector<typeB> & getList() const { return l; };
};
If you really really must have const typeB, you could instead return a projection of l that has added const, but that wouldn't be a Container, but instead a Range (using the ranges library voted into C++20, see also its standalone implementation)
std::shared_ptr<const typeB> add_const(std::shared_ptr<typeB> ptr)
{
return { ptr, ptr.get() };
}
class typeA {
std::vector<std::shared_ptr<typeB>> l;
public:
auto getList() const { return l | std::ranges::transform(add_const); };
};
Another alternative is that you can wrap your std::shared_ptrs in something like std::experimental::propagate_const, and just directly return them.
What you have here is a VERY complex construct:
shared_ptr<list<shared_ptr<typeB>>> l;
This is three levels of indirection, of which two have reference counting lifetime management, and the third is a container (and not memory-contiguous at that).
Naturally, given this complex structure, it is not going to be easy to convert it to another type:
shared_ptr<list<shared_ptr<const typeB>>>
Notice that std::list<A> and std::list<const A> are two distinct types by design of standard library. When you want to pass around non-modifying handles to your containers, you are usually supposed to use const_iterators.
In your case there is a shared_ptr on top of the list, so you can't use iterators if you want that reference counting behavior.
At this point comes the question: do you REALLY want that behavior?
Are you expecting a situation where your typeA instance is destroyed, but you still have some other typeA instances with the same container?
Are you expecting a situation where all your typeA instances sharing the container are destroyed, but you still have some references to that container in other places of your runtime?
Are you expecting a situation where the container itself is destroyed, but you still have some references to some of the elements?
Do you have any reason at all to use std::list instead of more conventional containers to store shared pointers?
If you answer YES to all the bullet points, then to achieve your goal you'll probably have to design a new class that would behave as a holder for your shared_ptr<list<shared_ptr<typeB>>>, while only providing const access to the elements.
If, however, on one of the bullet points your answer is NO, consider redesigning the l type. I suggest starting with std::vector<typeB> and then only adding necessary modifications one by one.
The problem with templates is that for any
template <typename T>
class C { };
any two pairs C<TypeA> and C<TypeB> are totally unrelated classes – this is even the case if TypeA and TypeB only differ in const-ness.
So what you actually want to have is technically not possible. I won't present a new workaround for now, as there are already, but try to look a bit further: As denoted in comments already, you might be facing a XY problem.
Question is: What would a user do with such a list? She/he might be iterating over it – or access single elements. Then why not make your entire class look/behave like a list?
class typeA
{
// wondering pretty much why you need a shared pointer here at all!
// (instead of directly aggregating the list)
shared_ptr<list<shared_ptr<typeB>>> l;
public:
shared_ptr<list<shared_ptr<typeB>>>::const_iterator begin() { return l->begin(); }
shared_ptr<list<shared_ptr<typeB>>>::const_iterator end() { return l->end(); }
};
If you used a vector instead of a list, I'd yet provide an index operator:
shared_ptr<typeB /* const or not? */> operator[](size_t index);
Now one problem yet remains unsolved so far: The two const_iterators returned have an immutable shared pointer, but the pointee is still mutable!
This is a bit of trouble - you'll need to implement your own iterator class now:
class TypeA
{
public:
class iterator
{
std::list<std::shared_ptr<int>>::iterator i;
public:
// implementation as needed: operators, type traits, etc.
};
};
Have a look at std::iterator for a full example – be aware, though, that std::iterator is deprecated, so you'll need to implement the type-traits yourself.
The iterator tag to be used would be std::bidirectional_iterator_tag or random_access_iterator_tag (contiguous_iterator_tag with C++20), if you use a std::vector inside.
Now important is how you implement two of the needed operators:
std::shared_ptr<int const> TypeA::iterator::operator*()
{
return std::shared_ptr<int const>(*i);
}
std::shared_ptr<int const> TypeA::iterator::operator->()
{
return *this;
}
The other operators would just forward the operation to the internal iterators (increment, decrement if available, comparison, etc).
I do not claim this is the Holy Grail, the path you need to follow under all circumstances. But it is a valuable alternative worth to at least consider...

Can I get away with putting auto_ptr in a STL container?

I am inheriting an interface, and implementing a virtual function that is supposed to do some work on a list of dynamically allocated objects. The first step is to remove duplicates from the list based on some custom equivalence criteria:
class Foo { /* ... */ };
struct FooLess
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
struct FooEqual
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
void doStuff(std::list<Foo*> &foos)
{
// use the sort + unique idiom to find and erase duplicates
FooLess less;
FooEqual equal;
foos.sort( foos.begin(), foos.end(), less );
foos.erase(
std::unique( foos.begin(), foos.end(), equal ),
foos.end() ); // memory leak!
}
The problem is that using sort + unique doesn't clean up the memory, and the elements to be erased have unspecified values after unique, so I cannot perform the cleanup myself before eraseing. I was considering something like this:
void doStuff(std::list<Foo*> &foos)
{
// make a temporary copy of the input as a list of auto_ptr's
std::list<auto_ptr<Foo>> auto_foos;
for (std::list<Foo>::iterator it = foos.begin(); it != foos.end(); ++it)
auto_foos.push_back(auto_ptr<Foo>(*it));
foos.clear();
FooLess less; // would need to change implementation to work on auto_ptr<Foo>
FooEqual equal; // likewise
auto_foos.sort( auto_foos.begin(), auto_foos.end(), less );
auto_foos.erase(
std::unique( auto_foos.begin(), auto_foos.end(), equal ),
auto_foos.end() ); // okay now, duplicates deallocated
// transfer ownership of the remaining objects back
for (std::list<auto_ptr<Foo>>::iterator it = auto_foos.begin();
it != auto_foos.end(); ++it)
{ foos.push_back(it->get()); it->release(); }
}
Will this be okay, or am I missing something?
I am not able to use C++11 (Boost might be possible) or change the function signature to accept a list of straightforward Foos.
To put an object into a standard container the object needs value semantics (the standard says "copy assignable" and "copy constructable"). Among other things, that means the copy constructor and assignment operator needs to create a copy of an object (leaving the original intact)
The auto_ptr copy constructor does not do that. Instead, the copy constructor and assignment operator transfer ownership of the pointer.
As a consequence, it is not possible for a standard container to contain an auto_ptr.
A lot of implementations (as in compiler and standard library) have the standard containers and/or auto_ptr coded so attempting to have a container of auto_ptr's will trigger a compiler error. Unfortunately, not all implementations do that.
There are generally the following methods you can use in C++98:
Define some pointer that will do what std::auto_ptr can't do. There was an old version of that thing, which contained an additional field of type bool that marked ownership. It was marked mutable, so it could be modified also in the object being read from when copying. The object was deleted at the end only if owned was true. Something like:
==
template <class T> class owning_ptr
{
T* ptr;
mutable bool owns;
public:
void operator =(T* src) { ptr = src; owns = true; }
owning_ptr(const owning_ptr& other)
{
// copy the pointer, but STEAL ownership!
ptr = other.ptr; owns = other.owns; other.owns = false;
}
T* release() { owns = false; return ptr; }
~owning_ptr() { if ( owns ) delete ptr; }
/* ... some lacking stuff ..*/
};
You may try out boost::shared_ptr
Instead of std::unique, you may try to do std::adjacent_find in a loop. Then you'll just find all elements that are "the same" as by your equal. If there's more than one element, you will erase them in place (you are allowed to do it because it's a list, so iterators remain valid).

operator== and vector confusion

I'm having some trouble keeping objects in a vector, and I think I need to do something with the operators.
std::vector<Foo> vec;
Foo a = Foo();
vec.push_back(a);
...
if(std::find(vec.begin(), vec.end(), a) < vec.end()) {
// Found
} else {
// Not found
}
Foo needs operator== to compile, I do this
bool Foo::operator==(const Foo& rhs) {
return this == &rhs;
}
But from what I understand, vec.push_back, is going to make a copy of the Foo object, so my == will return false.
Hence, whenever I get to the searching, it is never found.
What's the right thing to do here? I'm hoping to avoid switching to a vector of pointers.
Change the implementation of Foo::operator== to compare the member variables of Foo for equality instead of checking identity. For example:
bool Foo::operator==(const Foo& rhs) const {
return get_a() == rhs.get_a()
&& get_b() == rhs.get_b(); // and so on
}
Note that this can also be a const function since it should not modify any member variables and should be usable on const instances of Foo.
Your operator== implies that identity is defined by its location in memory, but the fact that you are appending values to a vector and hoping for equality says that identity is NOT defined by location.
If for some reason you don't have an identity definition based on any other members, you can add a unique identifier to your Foo objects, can compare that identifier in your code:
bool operator==(const Foo &rhs)
{
return this->m_id == rhs.m_id;
}
There is really nothing you can do, std::vector<> (or rather most standard containers) makes copies on insertions. If equality of two Foo objects is really defined by their addresses being equal the only thing you can do is to store pointers in the std::vector<>. If you want to store pointers in the std::vector<> I'd recommend storing smart-pointers instead like std::shared_ptr<>, std::unique_ptr<>.
If Foo's is too heavy to copy you can make Foo Move-only in C++11 or you can make it move only in C++03 using boost::containers::vector and boost::move.
Probably it is just easier to change the operator==() to compare the member variables instead.

C++ operator < overloading

I have a problem with overloading of the < operator.
I have this class:
WordEntry.h:
class WordEntry
{
public:
WordEntry(string word);
~WordEntry();
bool operator<(const WordEntry otherWordEntry);
string getWord();
private:
string _word;
};
WordEntry.cpp(I removed constructor & destructor):
string WordEntry::getWord()
{
return _word;
}
bool WordEntry::operator<(WordEntry otherWordEntry)
{
return lexicographical_compare(_word.begin(),_word.end(),otherWordEntry.getWord().begin(),otherWordEntry.getWord().end());
}
Everything is fine when I'm using it in main.cpp like that:
WordEntry w1("Der");
WordEntry w2("das");
if (w1.operator<(w2)) {
cout << "w1 > w2";
}
else
{
cout << "w2 > w1";
}
But when I call sort() on a vector with WordEntry objects, I'll get the error message
Invalid operands to binary expression ('const WordEntry' and 'const
WordEntry')
and it points to stl_algo.h.
Does anyone knows what's going on here?
Right now the argument to < is const but the member is not. This means a < comparison between 2 const WordEntry& objects will fail because it can't bind to <. You need to make the member and the argument both const
bool operator<(const WordEntry& otherWordEntry) const;
bool WordEntry::operator<(const WordEntry& otherWordEntry) const {
...
}
Note: As pointed out in the comments you should also pass WordEntry by reference
string WordEntry::getWord()
bool WordEntry::operator<(WordEntry otherWordEntry)
{
return lexicographical_compare(_word.begin(),
_word.end(),
otherWordEntry.getWord().begin(),
otherWordEntry.getWord().end());
}
The getWord member function creates a copy of the internal member attribute and returns the copy. Two consecutive calls to getWord will return two different std::string instances with the same contents, but they are different objects none the less. The lexicographical_compare function requires that the first and second arguments are iterators into the same container, and similarly the third and fourth arguments. In your case you are passing iterators into different containers (string), which will be compared inside the function and will yield undefined behavior.
The simplest solution is have getWord return a const reference to the internal std::string, in that way, the iterators will both refer to the internal object in the right hand side object.
As others have also mentioned, you should pass the WordEntry by const reference, and the operator< should be const, to improve the code. But the issue in your implementation is the mixture of iterators from different container.
Use a const reference for the rvalue and make the method const to promise the compiler you won't change the object.
bool operator<(const WordEntry& otherWordEntry) const
{
// comparison
}
You also don't need to explicitly call the operator.
Once defined for the WordEntry object you can do this:
if (w1 < w2) { // etc }
Since you aren't using a custom comparing predicate you could just use the std::string::operator<:
return _word < otherWordEntry._word;
David makes an excellent point on returning the internal member by value. If you want to use lexicographical_compare with an accessor instead of the _word member directly (which can as you're in the class scope) then you should define it like so:
const string& getWord() const { return _word; }