0

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.

jkoendev
  • 65
  • 1
  • 7
  • 1
    If the lifetime of the object whose pointer you added as key is equal to or longer than the lifetime of the map, then there's no problem. The objects can't change location. They can however change their contents (its "value") which won't be reflected in the sorting of sorted containers. – Some programmer dude Feb 18 '19 at 12:33
  • 3
    And as mentioned in the answers to the linked question, the key is not the object itself but only the pointer. The contents, or value, of the object is irrelevant for the map data structure. That means two objects that would otherwise compare equal will *not* be the same in the map. – Some programmer dude Feb 18 '19 at 12:35
  • 1
    Where are you getting the pointers from? If the `CustomClass` objects are owned by something like a `std::vector`, then you will have to worry about insertions into the vector invalidating the pointers and references – Caleth Feb 18 '19 at 12:43
  • Thanks a lot for the answers so far! I updated the question with a code example. – jkoendev Feb 18 '19 at 13:01
  • You can prevent the situation in the update by `= delete`ing the copy and move constructors of `SymPrimitive`. In general though, I recommend you familiarize yourself with the [rule of five/zero](https://en.cppreference.com/w/cpp/language/rule_of_three) and the concepts underlying ownership/lifetime management in C++ [in general](https://www.google.com/search?q=c%2B%2B+lifetime+management). You are trying to tie down a core design aspect of your library here, so it pays to understand the options C++ offers. – Max Langhof Feb 18 '19 at 14:30
  • Great recommendations, thanks! – jkoendev Feb 18 '19 at 16:28

2 Answers2

2

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.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thanks! I think this is not an issue in the test program, as the users need to pass the objects to define the Assignment and therefore the objects have to exist when evaluating the expression `d`. – jkoendev Feb 18 '19 at 13:31
  • I disagree with that, if the object is inside a collection (not through a pointer) its address can change because of an internal _realloc_ moving it. Am I wrong ? – bruno Feb 18 '19 at 13:46
  • 2
    @bruno it's no longer the same object after the operation. There is a new object, with the value copied from the old object. My last paragraph reminds the reader of the same caveat. – eerorika Feb 18 '19 at 13:48
  • you play with the word ^^ you consider an object is determined by its address so of course in that case there is no photo ;-) – bruno Feb 18 '19 at 13:49
  • 1
    @bruno that is how "object" is defined in the standard :) – eerorika Feb 18 '19 at 13:50
  • I just consider the question of the OP, so my answer. Of course with two different definitions of _objects_ we have 2 different results :-) – bruno Feb 18 '19 at 13:52
  • @bruno well, there is only one definition in the language, and that's what I assume the question is about. However, I did acknowledge the possibility that OP might have meant something else, which is why I added the last paragraph which would otherwise be redundant. – eerorika Feb 18 '19 at 13:57
  • I addressed the potential pitfall of passing a copy of the original object in an answer update. This will and should always lead to an error/failed lookup which i think is out of the scope of this question. – jkoendev Feb 18 '19 at 14:18
0

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...)

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
  • I think this answer explains it best + i add my insights from the discussions: 1. If you move an object to a different part of memory (new address) it is (by definition) a copy of the object. 2. You have to be careful when creating copies of the object because you are not able to use the copy for the map lookup (as it has a different address). – jkoendev Feb 18 '19 at 22:31