Are STL predicates allowed to use their argument's address? - c++

When writing a custom predicate function/functor to pass to an STL algorithm, is the predicate allowed to use the address of its argument?
Here's the problem that inspired the question. I have a vector vec, and a vector inds, which contains some indices into vec. I'd like to remove those elements in vec whose indices are listed in inds.
One approach is to use remove_if with a predicate functor InInds that determines its argument's index in vec by taking its address:
class InInds {
private:
const vector<Element>& vec_;
const vector<int>& inds_;
public:
InInds(const vector<Element>& vec, const vector<int>& inds)
: vec_(vec), inds_(inds) {}
bool operator()(const Element& element) {
// WARNING: uses the ADDRESS of element, not its value. May not be kosher?
int index = &element - &vec[0];
return std::find(inds_.begin(), inds_.end(), index) != inds_.end();
}
}
InInds works if called directly on an element in vec. It will break if it's called on a copy of an element, since the copy's address will not be useful to determine element's index.
My question is: will this predicate work in remove_if for any standards-compliant compiler? Or are predicates strictly meant to operate only on values, not addresses?

Use of remove_if with your predicate is wrong since remove_if usually moves undeleted elements toward the beginning of the range. You need to copy undeleted elements to another container instead of removing them in place.

Related

C++ STL algorithms: get pointers of elements in container

I have a function that is taking two pointers as parameters.
bool function(T* a, T* b);
And a container (vector).
vector<T> vector;
I wish to use an algorithm of the STL (the for_each) to apply the function on the elements of the vector. However, I don't know if the pointers of the elements will go automatically in the function as parameters. For example, will
for_each(vector.begin(), vector.end(), function(/*something here?*/))
work, or I need to go with a loop (the new for each in loop of the C++11) ?
You cannot use std::for_each() with your function for at least two reasons:
std::for_each passes a single parameter to the lamba, your function() takes two parameters.
std::for_each passes a reference to each member of the container, and not a pointer.
Try utilizing a normal for loop for solving this problem.
vector<T> v;
for(size_t i(0); i < v.size()-1; ++i)
{
function(&v[i], &v[i+1]);
}
This will pass as the values an address to elements i and i+1 of v which of type T.

which element will be returned from std::multimap::find, and similarly std::multiset::find?

Most likely this question is a duplicate but I could not find a reference to it.
I'm looking at std::multiset::find & std::multimap::find functions and I was wondering which element will be returned if a specific key was inserted multiple times?
From the description:
Notice that this function returns an iterator to a single element (of
the possibly multiple equivalent elements)
Question
Is it guaranteed that the single element is the first one inserted or is it random?
Background
The reason I'm asking is that I'm implementing multipmap like class:
typedef std::vector<Item> Item_vector;
class Item
{
string m_name;
};
class MyItemMultiMap
{
public:
// forgive me for not checking if key exist in the map. it is just an example.
void add_item( const Item& v ) { m_map[v.m_name].push_back(v); }
// is returning the first item in the vector mimic std::multimap::find behavior?
Item& get_item( const string& v ) { return m_map[v][0]; }
private:
std::map<string,Item_vector> m_map;
};
I'd like get_item() to work exactly as std::multimap::find. is it possible? if so, how would it be implemented?
The find method may return an arbitrary one if more than one is present, though your STL implementation might indeed just give the first one.
It's safer to use the 'lower_bound' method, and ++ iterate from there (see std::multimap::lower_bound). Do note though that 'lower_bound' returns a ref to another element if what you're looking for isn't present!
The C++ standard says that for any associative container a, a.find(k) "returns an iterator pointing to an element with the key equivalent to k, or a.end() if such an element is not found", and it doesn't impose any additional requirements on multimap. Since it doesn't specify which element is returned, the implementation is permitted to return any matching element.
If you're trying to imitate the exact behavior of multimap on the platform where you're running, that's bad news, but if your goal is just to satisfy the same requirements as multimap, it's good news: you can return any matching element that you want to, and in particular it's fine to just always return the first one.
http://en.cppreference.com/w/cpp/container/multimap/find
Finds an element with key key. If there are several elements with key
in the container, the one inserted earlier is selected.
So, an iterator to the first element will be returned.
In general, I find equal_range to be the more useful method, returning a pair of iterators pointing respectively at the first, and after the last, elements matching the key.

Erasing values from vector/map

Is this a safe way of deleting all entries from my vector or map
Vector
my_vector.erase(my_vector.begin(),my_vector.end());
For example for a map
my_map.erase(my_map.begin(),my_map.end());
The map or vector structure contains elements whose de-allocation is taken care in the destructor of those elements
Does the iterator value returned by end() become invalid as it starts to erase elements?
Both erase() methods are designed to work for iterator ranges excluding the second one.
// erase elements in range [a,b)
Iterator erase(Iterator a, Iterator b);
So it is safe to call erase() as you do, but you might as well call clear() in both cases.
It's safe to call erase(begin, end) for std::vector/std::map, it also valid to other STL containers(list, set, deque etc) which provide erase member function and iterator to iterate through elements.
As long as you pass in valid range(beg,end), below two ranges are also valid, erase takes no efforts:
c.erase(c.begin(), c.begin());
c.erase(c.end(), clend());
std::vector::erase(beg,end) Removes all elements of the range [beg,end) and returns the
position of the next element.
std::map::erase(beg,end) Removes all elements of the range [beg,end) and returns
the following position (returned nothing before C++11).
In STL internal implementation, it calls erase(begin,end) in a few functions like:
void clear() noexcept;
Effects: Behaves as if the function calls:
erase(begin(), end());
void assign(size_type n, const T& t);
Effects:
erase(begin(), end());
insert(begin(), first, last);
As you can see, erase(begin(),end()); is the same as clear().
Alternatively, you could call swap to clear a STL container which is suggested in More Effective STL:
vector<Contestant> v;
vector<Contestant>().swap(v); //clear v and minimize its capacity

std::sort and custom swap function

I currently have an array of pair<double, int> which I sort using a simple custom comparator function e.g.
// compare by first
int sort_index_lcomparator(const pair<double, int>& a, const pair<double, int>& b) {
return a.first < b.first;
}
// then sort simply like
pair<double, int> arr[size];
std::sort(arr, arr + size, sort_index_lcomparator);
I'm actually interested in the index order and not in the sorted doubles. My problem is that I would like to change away from this structure and have instead a struct of two arrays rather than an array of a struct i.e. I would like to optimize for locality and auto-vectorization but in this case I need an overloaded swap which is attached to a type specifically. I guess I would need something along the lines of redefining swap for the double type and keep both arrays in sync in such custom swap. Is there a way to "override" swap in such a manner within a limited scope?
I have one proposal for you: make the index array the one you sort and keep the values as global array. From then on: sort based on comparator that accepts indices, but actually compares based on the values.
You should specialize std::sort using your custom "comparator".
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
By default sort uses a standard comparator which just compares the elements referenced by the given iterators.
Using the custom Compare you may override this. Note that it's not a function (in C++ generally you may not pass a function as a template parameter). It's a class. You pass an object of this class to sort, whereas this object should implement the following operator:
bool operator () (const Type1 &a, const Type2 &b);
So, you may invoke sort for array of your double's. Your comparator should have pointers to the beginning of both your arrays: double and int.
In case with arrays the iterator resolves into a pointer to an array element. Using the array starting address you may convert it into an index, and use it to access the second array.

Why does std::vector transfer its constness to the contained objects?

A const int * and an int *const are very different. Similarly with const std::auto_ptr<int> vs. std::auto_ptr<const int>. However, there appears to be no such distinction with const std::vector<int> vs. std::vector<const int> (actually I'm not sure the second is even allowed). Why is this?
Sometimes I have a function which I want to pass a reference to a vector. The function shouldn't modify the vector itself (eg. no push_back()), but it wants to modify each of the contained values (say, increment them). Similarly, I might want a function to only change the vector structure but not modify any of its existing contents (though this would be odd). This kind of thing is possible with std::auto_ptr (for example), but because std::vector::front() (for example) is defined as
const T &front() const;
T &front();
rather than just
T &front() const;
There's no way to express this.
Examples of what I want to do:
//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();
//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();
It's a design decision.
If you have a const container, it usually stands to reason that you don't want anybody to modify the elements that it contains, which are an intrinsic part of it. That the container completely "owns" these elements "solidifies the bond", if you will.
This is in contrast to the historic, more lower-level "container" implementations (i.e. raw arrays) which are more hands-off. As you quite rightly say, there is a big difference between int const* and int * const. But standard containers simply choose to pass the constness on.
The difference is that pointers to int do not own the ints that they point to, whereas a vector<int> does own the contained ints. A vector<int> can be conceptualised as a struct with int members, where the number of members just happens to be variable.
If you want to create a function that can modify the values contained in the vector but not the vector itself then you should design the function to accept iterator arguments.
Example:
void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
std::for_each(begin, end, [](int& elem) { elem = 1; });
}
If you can afford to put the desired functionality in a header, then it can be made generic as:
template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
typedef typename iterator_traits<OutputIterator>::reference ref;
std::for_each(begin, end, [](ref elem) { elem = 1; });
}
One big problem syntactically with what you suggest is this: a std::vector<const T> is not the same type as a std::vector<T>. Therefore, you could not pass a vector<T> to a function that expects a vector<const T> without some kind of conversion. Not a simple cast, but the creation of a new vector<const T>. And that new one could not simply share data with the old; it would have to either copy or move the data from the old one to the new one.
You can get away with this with std::shared_ptr, but that's because those are shared pointers. You can have two objects that reference the same pointer, so the conversion from a std::shared_ptr<T> to shared_ptr<const T> doesn't hurt (beyond bumping the reference count). There is no such thing as a shared_vector.
std::unique_ptr works too because they can only be moved from, not copied. Therefore, only one of them will ever have the pointer.
So what you're asking for is simply not possible.
You are correct, it is not possible to have a vector of const int primarily because the elements will not assignable (requirements for the type of the element contained in the vector).
If you want a function that only modifies the elements of a vector but not add elements to the vector itself, this is primarily what STL does for you -- have functions that are agnostic about which container a sequence of elements is contained in. The function simply takes a pair of iterators and does its thing for that sequence, completely oblivious to the fact that they are contained in a vector.
Look up "insert iterators" for getting to know about how to insert something into a container without needing to know what the elements are. E.g., back_inserter takes a container and all that it cares for is to know that the container has a member function called "push_back".