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.)
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 .
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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.