I would like to use a std::map (or prob. std::unordered_map) where i insert custom object keys and double values, e.g. std::map<CustomClass,double>.
The order of the objects does not matter, just the (fast) lookup is important. My idea is to insert the address/pointer of the object instead as that has already have a comparator defined, i.e. std::map<CustomClass*,double>
In
Pointers as keys in map C++ STL
it has been answered that this can be done but i am still a bit worried that there might be side effects that are hard to catch later.
Specifically:
Can the address of an object change during runtime of the program? And could this lead to undefined behavior for my lookup in the map?
A test program could be:
auto a = adlib::SymPrimitive();
auto b = adlib::SymPrimitive();
auto c = adlib::mul(a,b);
auto d = adlib::add(c,a);
// adlib::Assignment holds std::map which assigns values to a,b
auto assignment = adlib::Assignment({&a,&b},{4,2});
// a=4, b=2 -> c=8 -> d=12
adlib::assertEqual(d.eval_fcn(assignment), 12);
which is user code, so users could potentially put the variables into a vector etc.
Update:
The answers let me think about users potentially inserting SymPrimitives into a vector, a simple scenario would be:
std::vector<adlib::SymPrimitive> syms{a,b};
auto assignment = adlib::Assignment({&syms[0],&syms[1]},{4,2}); // not allowed
The pitfall here is that syms[0] is a copy of a and has a different address. To be aware of that i could probably make the responsibility of the user.
Can the address of an object change during runtime of the program?
No. The address of an object never changes.
However, an object can stop existing at the address where it was created when the lifetime of the object ends.
Example:
std::map<CustomClass*,double> map;
{
CustomClass o;
map.emplace(&o, 3.14);
}
// the pointer within the map is now dangling; the pointed object does not exist
Also note that some operations on come containers cause the elements of the container to occupy a new object, and the old ones are destroyed. After such operation, references (in general sense; this includes pointers and iterators) to those elements are invalid and the behaviour of attempting to access through those references is undefined.
Objects never change address during their lifetime. If all you want to do is look up some value associated with an object whose address is known at the time of the lookup, then using the address of the object as the key in a map should be perfectly safe.
(It is even safe if the object has been destroyed and/or deallocated, as long as you don't dereference the pointer and only use it as a key for looking up an item in the map. But you might want to figure out how to remove entries from the map when objects are destroyed or for other reasons shouldn't be in the map any more...)
Here is the quote from "Effective STL":
When you get an object from a container (via. e.g., front or back), what you set is a copy of what was
contained. Copy in, copy out. That's the STL way.
I have had a hard time understanding this part. As far as I know front returns the reference of the first element (at least for std::vector).
Could you please explain above sentence?
This was actually an error in an earlier edition of the book. From the errata:
! 6/29/01 jk 20 The first para of Item 3 is incorrect: front 7/25/04
and back do NOT return copies of elements, they
return references to elements. I
removed all mention of front and back.
So the explanation of the sentence is: woops, time to get a new edition!
The idea with a statement like that is that when you want to get an element out of the container, you don't keep a reference or pointer to the element in the container, you create a copy of it (from the reference those methods return). The function returns, for back() and front(), are secondary concerns and likely confuse the issue - even the errata removed the mention of them.
Containers can undergo reallocation (especially vector) with you not necessarily being notified by the container, the elements are moved in memory and suddenly you have an invalid reference or pointer.
Bear in mind the time of the advice, before move semantics and movable objects etc. But the general principle still applies, don't keep references or pointers to objects that could become invalid.
"Value semantics" is a strong theme that not only runs through the standard library, but the whole of C++.
I want a container to store unique std::weak_ptrs. std:set requires operator<, presumably because it stores the items in a tree. My worry is if I implement operator< in the obvious way (destroyed ptr = null ptr < valid ptr) then this result can mutate after items are added to the container, which may break it.
Is this in fact safe? If not, any suggestions for a container?
Thanks
user3159253 is correct. Found the full answer here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1590.html
weak_ptr::operator<
Since a weak_ptr can expire at any time, it is not possible to order weak pointers based on their value. Accessing the value of a deleted pointer invokes undefined behavior, and reinterpret_cast tricks are no good, either, as the same pointer value can be reused by the next new expression. Using p.lock().get() for ordering is similarly flawed, as this implies that the value of p < q may change when p or q expires. If p and q are members of a std::set, this will break its invariant.
The only practical alternative is to order weak pointers by the address of their control block, as the current specification effectively demands.
You cannot use weak_ptrs as keys unless you use a owner based comparison (against the value based one, that is not even defined for weak_ptr, for which trying to use the operator< results in an error).
The problem is that they can expire and the ordering of your containers (a set as well as a map) wouldn't be consistent anymore.
As correctly pointed out by Kerrek SB (forgive me, but the mobile app does not let me to correctly link users) and as you can read from my link in the comments, you can rely on std::owner_less starting from C++11.
A valid approach is to use a set defined as it follows:
std::set<std::weak_ptr<C>, std::owner_less<std::weak_ptr<C>>>
Note that owner_less can be less verbose, for it deduces the type automatically.
Keep in mind that this approach does not keep you from invoking the expired method while visiting the set, because it can still contains expired objects even if consistently ordered.
Also, note that there is a huge difference between an expired weak_ptr and an empty one, so the owner based comparison could be not so intuitively, even if expiration shouldn't affect it once used the approach above mentioned.
Here some links.
I wish to take a reference to an object out of one C++ std::map and put it in another - eg to move an object from a low to a high priority tree.
If I erase the object from one tree, do I invalidate it completely? What if I have it in both trees at once and then erase (ie the object is referenced twice).
The documentation implies that the object will be invalidated in either case, but it's not 100% clear IMHO.
update here's an example - but looks to me that this just isn't going to work - using references at least - I'll have to use some form of pointer...
PartialPage oldPage = hTree->oldestPage();
lTree->insertOldPage(oldPage);
hTree->erase(oldPage);
NB oldestPage() returns a reference to a PartialPage
Containers own the elements within them, by virtue of storing their own copies. Your object is not in "both containers" at any time.
If you wish to introduced shared-resource semantics, you will have to store std::shared_ptr<PartialPage>s in your maps.
class MyContainedClass {
};
class MyClass {
public:
MyContainedClass * getElement() {
// ...
std::list<MyContainedClass>::iterator it = ... // retrieve somehow
return &(*it);
}
// other methods
private:
std::list<MyContainedClass> m_contained;
};
Though msdn says std::list should not perform relocations of elements on deletion or insertion, is it a good and common way to return pointer to a list element?
PS: I know that I can use collection of pointers (and will have to delete elements in destructor), collection of shared pointers (which I don't like), etc.
I don't see the use of encapsulating this, but that may be just me. In any case, returning a reference instead of a pointer makes a lot more sense to me.
In a general sort of way, if your "contained class" is truly contained in your "MyClass", then MyClass should not be allowing outsiders to touch its private contents.
So, MyClass should be providing methods to manipulate the contained class objects, not returning pointers to them. So, for example, a method such as "increment the value of the umpteenth contained object", rather than "here is a pointer to the umpteenth contained object, do with it as you wish".
It depends...
It depends on how much encapsulated you want your class to be, and what you want to hide, or show.
The code I see seems ok for me. You're right about the fact the std::list's data and iterators won't be invalidated in case of another data/iterator's modification/deletion.
Now, returning the pointer would hide the fact you're using a std::list as an internal container, and would not let the user to navigate its list. Returning the iterator would let more freedom to navigate this list for the users of the class, but they would "know" they are accessing a STL container.
It's your choice, there, I guess.
Note that if it == std::list<>.end(), then you'll have a problem with this code, but I guess you already know that, and that this is not the subject of this discussion.
Still, there are alternative I summarize below:
Using const will help...
The fact you return a non-const pointer lets the user of you object silently modify any MyContainedClass he/she can get his/her hands on, without telling your object.
Instead or returning a pointer, you could return a const pointer (and suffix your method with const) to stop the user from modifying the data inside the list without using an accessor approved by you (a kind of setElement ?).
const MyContainedClass * getElement() const {
// ...
std::list<MyContainedClass>::const_iterator it = ... // retrieve somehow
return &(*it);
}
This will increase somewhat the encapsulation.
What about a reference?
If your method cannot fail (i.e. it always return a valid pointer), then you should consider returning the reference instead of the pointer. Something like:
const MyContainedClass & getElement() const {
// ...
std::list<MyContainedClass>::const_iterator it = ... // retrieve somehow
return *it;
}
This has nothing to do with encapsulation, though..
:-p
Using an iterator?
Why not return the iterator instead of the pointer? If for you, navigating the list up and down is ok, then the iterator would be better than the pointer, and is used mostly the same way.
Make the iterator a const_iterator if you want to avoid the user modifying the data.
std::list<MyContainedClass>::const_iterator getElement() const {
// ...
std::list<MyContainedClass>::const_iterator it = ... // retrieve somehow
return it;
}
The good side would be that the user would be able to navigate the list. The bad side is that the user would know it is a std::list, so...
Scott Meyers in his book Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library says it's just not worth trying to encapsulate your containers since none of them are completely replaceable for another.
Think good and hard about what you really want MyClass for. I've noticed that some programmers write wrappers for their collections just as a matter of habit, regardless of whether they have any specific needs above and beyond those met by the standard STL collections. If that's your situation, then typedef std::list<MyContainedClass> MyClass and be done with it.
If you do have operations you intend to implement in MyClass, then the success of your encapsulation will depend more on the interface you provide for them than on how you provide access to the underlying list.
No offense meant, but... With the limited information you've provided, it smells like you're punting: exposing internal data because you can't figure out how to implement the operations your client code requires in MyClass... or possibly, because you don't even know yet what operations will be required by your client code. This is a classic problem with trying to write low-level code before the high-level code that requires it; you know what data you'll be working with, but haven't really nailed down exactly what you'll be doing with it yet, so you write a class structure that exposes the raw data all the way to the top. You'd do well to re-think your strategy here.
#cos:
Of course I'm encapsulating
MyContainedClass not just for the sake
of encapsulation. Let's take more
specific example:
Your example does little to allay my fear that you are writing your containers before you know what they'll be used for. Your example container wrapper - Document - has a total of three methods: NewParagraph(), DeleteParagraph(), and GetParagraph(), all of which operate on the contained collection (std::list), and all of which closely mirror operations that std::list provides "out of the box". Document encapsulates std::list in the sense that clients need not be aware of its use in the implementation... but realistically, it is little more than a facade - since you are providing clients raw pointers to the objects stored in the list, the client is still tied implicitly to the implementation.
If we put objects (not pointers) to
container they will be destroyed
automatically (which is good).
Good or bad depends on the needs of your system. What this implementation means is simple: the document owns the Paragraphs, and when a Paragraph is removed from the document any pointers to it immediately become invalid. Which means you must be very careful when implementing something like:
other objects than use collections of
paragraphs, but don't own them.
Now you have a problem. Your object, ParagraphSelectionDialog, has a list of pointers to Paragraph objects owned by the Document. If you are not careful to coordinate these two objects, the Document - or another client by way of the Document - could invalidate some or all of the pointers held by an instance of ParagraphSelectionDialog! There's no easy way to catch this - a pointer to a valid Paragraph looks the same as a pointer to a deallocated Paragraph, and may even end up pointing to a valid - but different - Paragraph instance! Since clients are allowed, and even expected, to retain and dereference these pointers, the Document loses control over them as soon as they are returned from a public method, even while it retains ownership of the Paragraph objects.
This... is bad. You've end up with an incomplete, superficial, encapsulation, a leaky abstraction, and in some ways it is worse than having no abstraction at all. Because you hide the implementation, your clients have no idea of the lifetime of the objects pointed to by your interface. You would probably get lucky most of the time, since most std::list operations do not invalidate references to items they don't modify. And all would be well... until the wrong Paragraph gets deleted, and you find yourself stuck with the task of tracing through the callstack looking for the client that kept that pointer around a little bit too long.
The fix is simple enough: return values or objects that can be stored for as long as they need to be, and verified prior to use. That could be something as simple as an ordinal or ID value that must be passed to the Document in exchange for a usable reference, or as complex as a reference-counted smart pointer or weak pointer... it really depends on the specific needs of your clients. Spec out the client code first, then write your Document to serve.
The Easy way
#cos, For the example you have shown, i would say the easiest way to create this system in C++ would be to not trouble with the reference counting. All you have to do would be to make sure that the program flow first destroys the objects (views) which holds the direct references to the objects (paragraphs) in the collection, before the root Document get destroyed.
The Tough Way
However if you still want to control the lifetimes by reference tracking, you might have to hold references deeper into the hierarchy such that Paragraph objects holds reverse references to the root Document object such that, only when the last paragraph object gets destroyed will the Document object get destructed.
Additionally the paragraph references when used inside the Views class and when passed to other classes, would also have to passed around as reference counted interfaces.
Toughness
This is too much overhead, compared to the simple scheme i listed in the beginning. It avoids all kinds of object counting overheads and more importantly someone who inherits your program does not get trapped in the reference dependency threads traps that criss cross your system.
Alternative Platforms
This kind-of tooling might be easier to perform in a platform that supports and promotes this style of programming like .NET or Java.
You still have to worry about memory
Even with a platform such as this you would still have to ensure your objects get de-referenced in a proper manner. Else outstanding references could eat up your memory in the blink of an eye. So you see, reference counting is not the panacea to good programming practices, though it helps avoid lots of error checks and cleanups, which when applied the whole system considerably eases the programmers task.
Recommendation
That said, coming back to your original question which gave raise to all the reference counting doubts - Is it ok to expose your objects directly from the collection?
Programs cannot exist where all classes / all parts of the program are truly interdependent of each other. No, that would be impossible, as a program is the running manifestation of how your classes / modules interact. The ideal design can only minimize the dependencies and not remove them totally.
So my opinion would be, yes it is not a bad practice to expose the references to the objects from your collection, to other objects that need to work with them, provided you do this in a sane manner
Ensure that only a few classes / parts of your program can get such references to ensure minimum interdependency.
Ensure that the references / pointers passed are interfaces and not concrete objects so that the interdependency is avoided between concrete classes.
Ensure that the references are not further passed along deeper into the program.
Ensure that the program logic takes care of destroying the dependent objects, before cleaning up the actual objects that satisfy those references.
I think the bigger problem is that you're hiding the type of collection so even if you use a collection that doesn't move elements you may change your mind in the future. Externally that's not visible so I'd say it's not a good idea to do this.
std::list will not invalidate any iterators, pointers or references when you add or remove things from the list (apart from any that point the item being removed, obviously), so using a list in this way isn't going to break.
As others have pointed out, you may want not want to be handing out direct access to the private bits of this class. So changing the function to:
const MyContainedClass * getElement() const {
// ...
std::list<MyContainedClass>::const_iterator it = ... // retrieve somehow
return &(*it);
}
may be better, or if you always return a valid MyContainedClass object then you could use
const MyContainedClass& getElement() const {
// ...
std::list<MyContainedClass>::const_iterator it = ... // retrieve somehow
return *it;
}
to avoid the calling code having to cope with NULL pointers.
STL will be more familiar to a future programmer than your custom encapsulation, so you should avoid doing this if you can. There will be edge cases that you havent thought about which will come up later in the app's lifetime, wheras STL is failry well reviewed and documented.
Additionally most containers support somewhat similar operations like begin end push etc. So it should be fairly trivial to change the container type in your code should you change the container. eg vector to deque or map to hash_map etc.
Assuming you still want to do this for a more deeper reason, i would say the correct way to do this is to implement all the methods and iterator classes that list implements. Forward the calls to the member list calls when you need no changes. Modify and forward or do some custom actions where you need to do something special (the reason why you decide to this in the first place)
It would be easier if STl classes where designed to be inherited from but for efficiency sake it was decided not to do so. Google for "inherit from STL classes" for more thoughts on this.