I'm kinda stuck with using a set with a pointer delegate. My code is as follows:
void Graph::addNodes (NodeSet& nodes)
{
for (NodeSet::iterator pos = nodes.begin(); pos != nodes.end(); ++pos)
{
addNode(*pos);
}
}
Here NodeSet is defined as:
typedef std::set<Node_ptr, Node_ptr_Sorting_Predicate> NodeSet;
The above piece of code works perfectly on my windows machine, but when I run the same piece of code on a MAC, it gives me the following error:
no matching function for call to 'Graph::addNode(const boost::shared_ptr<Node>&)'
FYI, Node_ptr is of type: typedef boost::shared_ptr<Node> Node_ptr;
Can somebody please tell me why this is happening?
Ok, from your added information, the problem seems to be that addNode takes a Node_ptr per non-const reference, while what the compiler has to call the function is a const boost::shared_ptr<Node>& (note the const). Let me explain:
std::set is an associative container. Associative containers store their elements in some order, using the key element to define the ordering. If you would be allowed to change the key without the container knowing, you would invalidate the container's internal order. That's why I believe dereferencing a std::set<T>::iterator does not return an modifiable lvalue. (Which means you cannot alter the reference returned. For example, if you have an iterator pos into a std::set<int>, *pos=42 should not compile.)
The catch with this is that only modifiable lvalues will bind to a non-const reference. But what *pos returns isn't a modifiable lvalue and thus won't. (So, in my example, int& r = *pos; won't compile.) The reason is that, if this was allowed, you could change the sorting key through that non-const reference behind the container's back and mess up the container's internal ordering.
That is why the result of your *pos won't bind to a Node_ptr&. And that in turn is why the compiler cannot call your function.
Does your addNode() member function really alter the Node it's given? If not, it should take a const Node_ptr&.
If it does, you have a design problem. You cannot alter an element that's in a set. The only thing you can do is to remove it from the set, change it, and add it back in.
On a side note: VC9 indeed compiles the following piece of code:
#include <iostream>
#include <set>
#include <typeinfo>
#include <iterator>
int main()
{
std::set<int> set;
set.insert(5);
std::cout << *set.begin() << '\n';
*set.begin() = 3; // this is an error!
std::cout << *set.begin() << '\n';
return (0);
}
I believe this is an error in VC9. Comeau rejects it.
Here's how to solve riddles with a compiler not calling a function you think it should call or calling the wrong function from a set of overloads.
The function you thought it should call is Graph::addNode(Node_ptr&). The code that you thought should call it is
addNode(*pos);
Change that code so that it provides the exact parameter(s) required:
Node_ptr& tmp = *pos;
addNode(tmp);
Now the call should definitely compile (or call the right overload), and the compiler should bark if it thinks *pos cannot be assigned to to a Node_ptr&.
Usually this tactic helps me to find out what's wrong in such situations.
If memory serves, the original C++ spec (1998) permits std::set to return modifiable iterators. This carries with it a risk--the iterator might be used to modify the stored value, such that the ordering of the set is now broken. I believe subsequent versions of the spec have changed this, and now all set iterators are non-modifiable.
VC++ 2010 respects the new behaviour, and has non-modifiable set iterators (which is annoying, as it prevents making changes that don't change the ordering and which ought to be legal).
Prior versions, however, did not. This means that you can create functions that are not suitably annotated with const, which will cause problems on switching to different compilers. The solution is to add the necessary const changes. VC++ will still work (since non-const values can be implicitly made const anyway), and so will everything else.
Related
take a look at the following code:
#include <algorithm>
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> in {1,2,3};
deque<int> out;
// line in question
move(in.begin(), in.end(), out.begin());
for(auto i : out)
cout << i << endl;
return 0;
}
This will not move anything. Looking at the example here, one must write the line in question like this:
move(in.begin(), in.end(), std::back_inserter(out));
This makes sense in a way, as std::move expects its first two arguments to be InputInterators (which is satisfied here) and the third one to be an OutputIterator (which out.begin() is not).
What does actually happen if the original code is executed and move is passed an iterator that is not an OutputIterator? Why does C++'s type-safety not work here? And why is the construction of an output-iterator delegated to an external function, i.e. why does out.backInserter() not exist?
The original code tries to dereference and increment out.begin(). Since out is empty, that's a past-the-end iterator, and it can't be dereferenced or incremented. Doing so gives undefined behaviour.
std::move expects [...] the third one to be an OutputIterator (which out.begin() is not).
Yes it is. Specifically, it's a mutable random access iterator, which supports all the operations required of an output iterator, and more.
What does actually happen if the original code is executed and move is passed an iterator that is not an OutputIterator?
That would cause a compile error if the iterator didn't support the operations required of an output iterator needed by the function; or undefined behaviour if the operations existed but did something other than that required of an output iterator.
Why does C++'s type-safety not work here?
Because the type is correct. The incorrect runtime state (being a past-the-end iterator, not the start of a sequence with at least as many elements as the input range) can't be detected through the static type system.
why does out.backInserter() not exist?
That would have to be written separately for all sequence containers: both the standard ones, and any others you might define yourself. The generic function only has to be implemented once, in the standard library, to be usable for any container that supports push_back.
Is there any way to convert a vector::iterator into a pointer without having access to the vector itself? This works only if the vector is available:
typedef vector<int> V;
int* to_pointer1( V& v, V::iterator t )
{
return v.data() + (t-v.begin() );
}
But how can this be done without having the vector around? This wouldn't work:
int* to_pointer2( V::iterator t )
{
// the obvious approach doesn't work for the end iterator
return &*t;
}
In fact I would have expected this to be a very basic and popular question but for some reason I couldn't find it.
In general you are not guaranteed that there is a pointer corresponding to an iterator that refers to an ordinary vector item.
In particular std::vector<bool> is specialized so that &*it won't even compile.
However, for other vectors it's only1 the formally-pedantic that stops you from doing &*it also for the end iterator. In C99 it is, as I recall, formally valid to do &*p when p is an end pointer, and a goal of std::vector is to support all ordinary raw array notation. If I needed this I would just ignore the formal-pedantic, and write code with a view towards some future revision of the standard that would remove that imagined obstacle.
So, in practice, just do &*it. :)
#include <iostream>
#include <vector>
using namespace std;
auto main() -> int
{
vector<int> x( 5 );
cout << &*x.begin() << " " << &*x.end() << endl;
cout << &*x.end() - &*x.begin() << endl; // Works nicely IN PRACTICE.
}
But do remember that you can't do this for vector<bool>.
1) In a comment elsewhere user pentadecagon remarks: “Try -D_GLIBCXX_DEBUG, as documented here: gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode_using.html.” g++ often provides some means of bringing any formal UB to the front, e.g. “optimization” of formally UB loops. A solution in this particular case is simply to not ask it to do this, but more generally one may have to explicitly ask it to not do it.
No, this is not currently possible. n3884 Contiguous Iterators: A Refinement of Random Access Iterators proposes a free function std::pointer_from which would satisfy your requirement:
Expression: std::pointer_from(a)
Return type: reference
Operational semantics: if a is dereferenceable, std::address_of(*a); otherwise, if a is reachable from a dereferenceable iterator b, std::pointer_from(b) + (a – b); otherwise a valid pointer value ([basic.compound]).
What you are asking is not possible for the end iterator; By definition, the end iterator points to a hypothetical element past the end of the array (i.e. de-referencing it, is always UB).
You said:
#Nick I want it to work for any valid iterator, including the end. It should be possible, because to_pointer1 also covers this case.
to_pointer1 doesn't cover this case. to_pointer1 returns an invalid memory address (Actually the address is probably valid, but there is no data there).
I use this template:
template<typename It>
inline auto ptr(It const&it) -> decltype(std::addressof(*it))
{ return std::addressof(*it); }
In practice, this will work for most iterators. Exceptions are objects where either *it is not defined (vector<bool>::iterator) or where it points to nowhere (rather than to an past-the-last element). For your particular purpose, it shall be okay, except for vector<bool> (when the concept of a pointer is not sensible).
Is it dangerous to returning a pointer out of a std::map::find to the data and using that as opposed to getting a copy of the data?
Currently, i get a pointer to an entry in my map and pass it to another function to display the data. I'm concerned about items moving causing the pointer to become invalid. Is this a legit concern?
Here is my sample function:
MyStruct* StructManagementClass::GetStructPtr(int structId)
{
std::map<int, MyStruct>::iterator foundStruct;
foundStruct= myStructList.find(structId);
if (foundStruct== myStructList.end())
{
MyStruct newStruct;
memset(&newStruct, 0, sizeof(MyStruct));
myStructList.structId= structId;
myStructList.insert(pair<int, MyStruct>(structId, newStruct));
foundStruct= myStructList.find(structId);
}
return (MyStruct*) &foundStruct->second;
}
It would undoubtedly be more typical to return an iterator than a pointer, though it probably makes little difference.
As far as remaining valid goes: a map iterator remains valid until/unless the item it refers to is removed/erased from the map.
When you insert or delete some other node in the map, that can result in the nodes in the map being rearranged. That's done by manipulating the pointers between the nodes though, so it changes what other nodes contain pointers to the node you care about, but does not change the address or content of that particular node, so pointers/iterators to that node remain valid.
As long as you, your code, and your development team understand the lifetime of std::map values ( valid after insert, and invalid after erase, clear, assign, or operator= ), then using an iterator, const_iterator, ::mapped_type*, or ::mapped_type const* are all valid. Also, if the return is always guaranteed to exist, then ::mapped_type&, or ::mapped_type const& are also valid.
As for wise, I'd prefer the const versions over the mutable versions, and I'd prefer references over pointers over iterators.
Returning an iterator vs. a pointer is bad:
it exposes an implementation detail.
it is awkward to use, as the caller has to know to dereference the iterator, that the result is an std::pair, and that one must then call .second to get the actual value.
.first is the key that the user may not care about.
determining if an iterator is invalid requires knowledge of ::end(), which is not obviously available to the caller.
It's not dangerous - the pointer remains valid just as long as an iterator or a reference does.
However, in your particular case, I would argue that it is not the right thing anyway. Your function unconditionally returns a result. It never returns null. So why not return a reference?
Also, some comments on your code.
std::map<int, MyStruct>::iterator foundStruct;
foundStruct = myStructList.find(structId);
Why not combine declaration and assignment into initialization? Then, if you have C++11 support, you can just write
auto foundStruct = myStructList.find(structId);
Then:
myStructList.insert(pair<int, MyStruct>(structId, newStruct));
foundStruct = myStructList.find(structId);
You can simplify the insertion using make_pair. You can also avoid the redundant lookup, because insert returns an iterator to the newly inserted element (as the first element of a pair).
foundStruct = myStructList.insert(make_pair(structId, newStruct)).first;
Finally:
return (MyStruct*) &foundStruct->second;
Don't ever use C-style casts. It might not do what you expect. Also, don't use casts at all when they're not necessary. &foundStruct->second already has type MyStruct*, so why insert a cast? The only thing it does is hide a place that you need to change if you ever, say, change the value type of your map.
Yes,
If you build a generic function without knowing the use of it, it can be dangerous to return the pointer (or the iterator) since it can become un-valid.
I would advice do one of two:
1. work with std::shared_ptr and return that. (see below)
2. return the struct by value (can be slower)
//change the difination of the list to
std::map<int, std::shared_ptr<MyStruct>>myStructList;
std::shared_ptr<MyStruct> StructManagementClass::GetStructPtr(int structId)
{
std::map<int, std::shared_ptr<MyStruct>>::iterator foundStruct;
foundStruct = myStructList.find(structId);
if (foundStruct == myStructList.end())
{
MyStruct newStruct;
memset(&newStruct, 0, sizeof(MyStruct));
myStructList.structId= structId;
myStructList.insert(pair<int, shared_ptr<MyStruct>>(structId, shared_ptr<MyStruct>(newStruct)));
foundStruct= myStructList.find(structId);
}
return foundStruct->second;
Given the code in Visual Studio 2010:
void Foo::Bar() const
{
map_t::const_iterator iter(my_map_.find(key));
if(my_map_.end() != iter)
DoStuff(iter->second);
}
Do stuff will take the mapped_type by value. The mapped type is a copyable, movable, assignable type.
I get error messages that the key/value pair can't be copied when trying to access second. Even if I write on their own lines:
iter->second;
(*iter).second;
to ensure it's nothing to do with DoStuff...
I presume the iterator is making a copy of the key/value pair before returning operator-> or operator*.
How do I get a copy of the mapped type?
EDIT:
The map itself is of unsigned shorts to boost variants, roughly as such:
typedef struct{} empty_t;
typedef boost::variant<empty_t, double, long, some POD types> variant_t;
typedef std::map<unsigned short, variant_t> map_t;
And then as a private member of the class:
map_t my_map_;
And to be clear, the problem is not in passing to DoStuff. I can remove that line, and simply dereference the iterator and access second, and that will cause the compiler error.
if(my_map_.end() != iter)
iter->second; //Doesn't do anything, but illustrates the error.
EDIT
Answer invalid given question update as a result of boost::variant (will update with final answer once the rest of the problem information is available).
If DoStuff takes it's variable by reference or by value and you're passing the variable directly from a const_iterator then DoStuff must have a const reference or const value overloaded function call (unless the object type has a default const to non-const conversion available). Otherwise the compiler complains because your treating a const element as a non-const.
Another option is to assign iter->second to another variable (via constructor or assignment depending on the element type) and pass that into DoStuff -- but it's better to define a const overload version of the function.
I figured it out.
WAYYYYY away from this code, and a couple abstractions deep, the iterators to the map were being passed to std::partition! You can't partition a map, it seems.
I copied the contents of the map into a local vector and continued processing from there, and it cleared up all the error messages.
I have no idea why the compiler was getting so throughly confused. The problem code was somewhere completely unrelated. But it doesn't matter.
I have read Effective C++ 3rd Edition written by Scott Meyers.
Item 3 of the book, "Use const whenever possible", says if we want to prevent rvalues from being assigned to function's return value accidentally, the return type should be const.
For example, the increment function for iterator:
const iterator iterator::operator++(int) {
...
}
Then, some accidents is prevented.
iterator it;
// error in the following, same as primitive pointer
// I wanted to compare iterators
if (it++ = iterator()) {
...
}
However, iterators such as std::vector::iterator in GCC don't return const values.
vector<int> v;
v.begin()++ = v.begin(); // pass compiler check
Are there some reasons for this?
I'm pretty sure that this is because it would play havoc with rvalue references and any sort of decltype. Even though these features were not in C++03, they have been known to be coming.
More importantly, I don't believe that any Standard function returns const rvalues, it's probably something that wasn't considered until after the Standard was published. In addition, const rvalues are generally not considered to be the Right Thing To Do™. Not all uses of non-const member functions are invalid, and returning const rvalues is blanketly preventing them.
For example,
auto it = ++vec.begin();
is perfectly valid, and indeed, valid semantics, if not exactly desirable. Consider my class that offers method chains.
class ILikeMethodChains {
public:
int i;
ILikeMethodChains& SetSomeInt(int param) {
i = param;
return *this;
}
};
ILikeMethodChains func() { ... }
ILikeMethodChains var = func().SetSomeInt(1);
Should that be disallowed just because maybe, sometimes, we might call a function that doesn't make sense? No, of course not. Or how about "swaptimization"?
std::string func() { return "Hello World!"; }
std::string s;
func().swap(s);
This would be illegal if func() produced a const expression - but it's perfectly valid and indeed, assuming that std::string's implementation does not allocate any memory in the default constructor, both fast and legible/readable.
What you should realize is that the C++03 rvalue/lvalue rules frankly just don't make sense. They are, effectively, only part-baked, and the minimum required to disallow some blatant wrongs whilst allowing some possible rights. The C++0x rvalue rules are much saner and much more complete.
If it is non-const, I expect *(++it) to give me mutable access to the thing it represents.
However, dereferencing a const iterator yields only non-mutable access to the thing it represents. [edit: no, this is wrong too. I really give up now!]
This is the only reason I can think of.
As you rightly point out, the following is ill-formed because ++ on a primitive yields an rvalue (which can't be on the LHS):
int* p = 0;
(p++)++;
So there does seem to be something of an inconsistency in the language here.
EDIT: This is not really answering the question as pointed in the comments. I'll just leave the post here in the case it's useful anyhow...
I think this is pretty much a matter of syntax unification towards a better usable interface. When providing such member functions without differentiating the name and letting only the overload resolution mechanism determine the correct version you prevent (or at least try to) the programmer from making const related worries.
I know this might seem contradictory, in particular given your example. But if you think on most of the use cases it makes sense. Take an STL algorithm like std::equal. No matter whether your container is constant or not, you can always code something like bool e = std::equal(c.begin(), c.end(), c2.begin()) without having to think on the right version of begin and end.
This is the general approach in the STL. Remember of operator[]... Having in the mind that the containers are to be used with the algorithms, this is plausible. Although it's also noticeable that in some cases you might still need to define an iterator with a matching version (iterator or const_iterator).
Well, this is just what comes up to my mind right now. I'm not sure how convincing it is...
Side note: The correct way to use constant iterators is through the const_iterator typedef.