0

I have the following structure:

struct CacheNode {
  set<int> *value;
  int timestamp;
  CacheNode() : value(new set<int>()), timestamp(0) {}
};

And I pre-allocate a vector of them as follows:

vector<CacheNode> V(10);

When I do this, every CacheNode element in the vector points to the same set<int> in its value field. In particular,

  V[0].value->insert(0);
  cout << V[1].value->size() << endl;

prints out 1 instead of the 0 that I want.

What is the correct way to pre-allocate the vector (or to declare the structure) so that each CacheNode have its own set<int> instance?

(Note: I do need the value to be a pointer to a set, because it is possible in my application for some CacheNodes to share sets.)

4

3 に答える 3

5

vector<CacheNode> V(10); creates an initial CacheNode object and then copies it 10 times. So you have 10 identical objects.

You can use generate_n:

std::vector<CacheNode> v;
std::generate_n(std::back_inserter(v), 10u, [](){ return CacheNode{}; });

Here's an example program.

于 2013-03-23T01:54:25.587 に答える
5

You have violated the rule of 3. You have created an object with a non-trivial constructor, and failed to create a destructor or copy constructor or operator=.

std::vector<blah> foo(10) creates a single default constructed blah, and makes 10 copies of it in foo. Because you violated the rule of 3, these 10 copies are all identical.

The easiest method would be to do away with the new:

struct CacheNode {
  std::set<int> value;
  int timestamp;
  CacheNode() : value(), timestamp(0) {}
};

another route would be to use a unique_ptr for lifetime management, and explicitly copy:

struct CacheNode {
  std::unique_ptr<std::set<int>> value;
  int timestamp;
  CacheNode() : value(new std::set<int>()), timestamp(0) {}
  CacheNode(CacheNode&&) = default; // C++11 feature
  CacheNode(CacheNode const& other):value(new std::set<int>( *other.value ) ), timestampe(other.timestamp) {}

  CacheNode& operator=(CacheNode const& other) {
    value.reset(new std::set<int>(*other.value));
    timestampe = other.timestamp;
    return *this;
  }
  CacheNode& operator=(CacheNode&& other) = default;
  // no need for ~CacheNode, unique_ptr handles it
};

when you want to take the std::set<int> out of your CacheNode, call CacheNode().value.release() and store the resulting std::set<int>*.

std::shared_ptr<std::set<int>> would allow shared ownership of the std::set.

There are other approaches, including making your vector store pointers to CacheNode, creating value_ptr<T> templates that do value semantics, etc.

In C++11, these are relatively easy and safe, because std::vector will move things around, and move semantics on a value_ptr<T> won't create a new T.

I am a bit leery of your plan to have shared std::set<int> between different CacheNode, because in general that is bad smell -- the ownership/lifetime of things should be clear, and in this case you have some CacheNode that own the std::set<int> and others that don't (because they share ownership). A shared_ptr can get around this, but often there are better solutions.

于 2013-03-23T01:55:48.360 に答える
-1

You will want to use vector.assign(10, CacheNode()) as what your doing is a way of reserving space mostly.

Also you should do what the other ones say, provide virtual destructor and such.

于 2013-03-23T01:57:59.430 に答える