开发者

Why is the address of an object added to a C++ STL vector different than its original address?

I've got a very simple method that adds a node to a graph:

  template<class T>
  void AdjacencyList<T>::add(const GraphNode<T>& node) {
    _nodes.push_back(node);
  }

In another method, I iterate over the _nodes vector, looking for the added node by address:

for (unsigned int 开发者_运维知识库i = 0; i < _nodes.size(); i++) {
  if (&(_nodes[i]) == &node)
    // do something
}

However, this does not work, because when I add node to the _nodes vector, the added member has a different address:

Graph::AdjacencyList<int>::add (this=0x8052338, node=...) at ../AdjacencyList.h:42
42      _nodes.push_back(node);
(gdb) p node
$1 = (const Graph::GraphNode<int> &) @0xbffff39c: {value = 123}
(gdb) n
43      }
(gdb) p _nodes[0]
$4 = (Graph::GraphNode<int> &) @0x80522b0: {value = 123}

What in the world is going on here? And more importantly, how should I be adding a member to a vector so that I can find it later?


The object is copied into the vector, so the address of the copy stored inside the vector is surely different from the address of the original object since no two distinct objects can have identical addresses.

To find your object later you can either compare it by some other property (one of more of its member variables) or store its index in the vector somewhere. The usual approach is that every object has some "identifier" member variable that is unique at least for all objects stored inside one vector.


Because it's a different object. All standard containers own their objects and all types that you use in standard containers must be copyable.

When you pass an object to push_back it is copied into the vector. If you want to be able to find it later your object type must have a concept of equality where you can compare and find equivalent objects. (Either that, or you must remember which location you placed each object in the vector.)


If you do not want to push a copy of your object (of type T) into the container, you can use a container of smart pointers of T :

 std::vector< std::shared_ptr< Graph::GraphNode<int> > > c;

 std::shared_ptr< Graph::GraphNode<int> > p = std::shared_ptr< Graph::GraphNode<int> >(new Graph::GraphNode<int>(whatever));
 c.push_back(c);

With this you can compare the pointer.

You can use auto_ptr, shared_ptr, unique_ptr (or boost smart pointers [2]) depending on your needs.

Boost has pointer containers as well [1].

Also, look how graph are implemented in Boost.Graph [3]. You might want to use a similar approach.

[1] http://www.boost.org/doc/libs/1_46_1/libs/ptr_container/doc/ptr_container.html

[2] http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm

[3] http://www.boost.org/doc/libs/1_46_1/libs/graph/doc/table_of_contents.html


As a rule of thumb remember that STL uses copy semantics. So unless the STL container is a collection of pointers, any element added to a STL collection will be copied.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜