STL vector of pointers question
-
I have two vectors holding different classes. The first class contains only data of integer/double type. I can create a vector of the first class, access it, manipulate it, no problems. The second class contains a combination of data and several pointers to allocated storage space. The space is allocated on the fly as needed. The destructor of the class frees the space. The problem arises when adding new instances of the class to the vector. If there isn't enough space in the vector, the vector class clones itself, adds space, and the erases the old vector. Unfortunately in erasing "old" vector, it frees the storage space and the program crashes because the storage pointers are invalid. Creating a vector of pointers to the class solves the problem but would involve a massive re-write of code. Anyone have any suggestions how to handle this? Is there a graceful way to handle pointers inside the class when you don't know when the class will be destroyed by the container?
-
I have two vectors holding different classes. The first class contains only data of integer/double type. I can create a vector of the first class, access it, manipulate it, no problems. The second class contains a combination of data and several pointers to allocated storage space. The space is allocated on the fly as needed. The destructor of the class frees the space. The problem arises when adding new instances of the class to the vector. If there isn't enough space in the vector, the vector class clones itself, adds space, and the erases the old vector. Unfortunately in erasing "old" vector, it frees the storage space and the program crashes because the storage pointers are invalid. Creating a vector of pointers to the class solves the problem but would involve a massive re-write of code. Anyone have any suggestions how to handle this? Is there a graceful way to handle pointers inside the class when you don't know when the class will be destroyed by the container?
Having a copy constructor for the second class should solve the problem.
«_Superman_» I love work. It gives me something to do between weekends.
-
I have two vectors holding different classes. The first class contains only data of integer/double type. I can create a vector of the first class, access it, manipulate it, no problems. The second class contains a combination of data and several pointers to allocated storage space. The space is allocated on the fly as needed. The destructor of the class frees the space. The problem arises when adding new instances of the class to the vector. If there isn't enough space in the vector, the vector class clones itself, adds space, and the erases the old vector. Unfortunately in erasing "old" vector, it frees the storage space and the program crashes because the storage pointers are invalid. Creating a vector of pointers to the class solves the problem but would involve a massive re-write of code. Anyone have any suggestions how to handle this? Is there a graceful way to handle pointers inside the class when you don't know when the class will be destroyed by the container?
In addition to Superman's answer - you need to create an assignment operator that manages your memory as well. Something like this:
class A
{
public:
A(int i) : pi_(new int(i)) {}
A(const A& a) : pi_(new int(*a.pi_)) {}
A& operator=(const A& a)
{
*pi_ = *a.pi_;
}
~A() { delete pi_; }
private:
int* pi_;
};The other way round this is to manage your storage with (for example) Boost shared pointers[^].
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
In addition to Superman's answer - you need to create an assignment operator that manages your memory as well. Something like this:
class A
{
public:
A(int i) : pi_(new int(i)) {}
A(const A& a) : pi_(new int(*a.pi_)) {}
A& operator=(const A& a)
{
*pi_ = *a.pi_;
}
~A() { delete pi_; }
private:
int* pi_;
};The other way round this is to manage your storage with (for example) Boost shared pointers[^].
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
When would the assignment operator be used?
«_Superman_» I love work. It gives me something to do between weekends.
-
When would the assignment operator be used?
«_Superman_» I love work. It gives me something to do between weekends.
Any method that rearranges items in the vector. An example - the erase method (if you erase any except the last element). Consider this example code:
#include <iostream>
#include <vector>class Test
{
public:
Test() { std::cout << "Test::Test()\n"; }
Test( Test const& ) { std::cout << "Test::Test( Test const& )\n"; }
Test& operator=( Test const& ) { std::cout << "Test::operator=( Test const& )\n"; return *this; }
~Test() { std::cout << "Test::~Test()\n"; }
};int main (int argc, char const* argv[])
{
std::vector<Test> a;
std::cout << "push_back\n";
a.push_back(Test());
a.push_back(Test());
a.push_back(Test());
std::cout << "iterator\n";
std::vector<Test>::iterator it = a.begin();
++it;
std::cout << "erase\n";
a.erase(it);
return 0;
}It produces this output (with VS2008):
push_back
Test::Test()
Test::Test( Test const& )
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()
iterator
erase
Test::operator=( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Any method that rearranges items in the vector. An example - the erase method (if you erase any except the last element). Consider this example code:
#include <iostream>
#include <vector>class Test
{
public:
Test() { std::cout << "Test::Test()\n"; }
Test( Test const& ) { std::cout << "Test::Test( Test const& )\n"; }
Test& operator=( Test const& ) { std::cout << "Test::operator=( Test const& )\n"; return *this; }
~Test() { std::cout << "Test::~Test()\n"; }
};int main (int argc, char const* argv[])
{
std::vector<Test> a;
std::cout << "push_back\n";
a.push_back(Test());
a.push_back(Test());
a.push_back(Test());
std::cout << "iterator\n";
std::vector<Test>::iterator it = a.begin();
++it;
std::cout << "erase\n";
a.erase(it);
return 0;
}It produces this output (with VS2008):
push_back
Test::Test()
Test::Test( Test const& )
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()
iterator
erase
Test::operator=( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Wow, that explains a lot of the weird performance issues. Constructing large vectors (200-500) entries is what's taking up so much time. I am going with the vector of pointers because de-referencing them is fast compared to copying what can turn into very large classes. I am also reserving enough space so they won't constantly be copying themselves. Thanks very much for the code example, it was very illuminating.
-
Wow, that explains a lot of the weird performance issues. Constructing large vectors (200-500) entries is what's taking up so much time. I am going with the vector of pointers because de-referencing them is fast compared to copying what can turn into very large classes. I am also reserving enough space so they won't constantly be copying themselves. Thanks very much for the code example, it was very illuminating.
mjackson11 wrote:
Constructing large vectors (200-500) entries is what's taking up so much time
Large? That's not large :) I've tended to use
vector
s of Boost.SharedPointers[^] in the past, so I don't need to worry about deallocation (and also, it's easier to create indices into that vector, as you can just copy and re-sort the vector of smart pointers). That's been good for vectors with upwards of 10000 elements. Another (and probably better) alternative would be a Boost pointer container[^].Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Any method that rearranges items in the vector. An example - the erase method (if you erase any except the last element). Consider this example code:
#include <iostream>
#include <vector>class Test
{
public:
Test() { std::cout << "Test::Test()\n"; }
Test( Test const& ) { std::cout << "Test::Test( Test const& )\n"; }
Test& operator=( Test const& ) { std::cout << "Test::operator=( Test const& )\n"; return *this; }
~Test() { std::cout << "Test::~Test()\n"; }
};int main (int argc, char const* argv[])
{
std::vector<Test> a;
std::cout << "push_back\n";
a.push_back(Test());
a.push_back(Test());
a.push_back(Test());
std::cout << "iterator\n";
std::vector<Test>::iterator it = a.begin();
++it;
std::cout << "erase\n";
a.erase(it);
return 0;
}It produces this output (with VS2008):
push_back
Test::Test()
Test::Test( Test const& )
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::Test()
Test::Test( Test const& )
Test::Test( Test const& )
Test::Test( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()
iterator
erase
Test::operator=( Test const& )
Test::~Test()
Test::~Test()
Test::~Test()Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Thanks. That is new information. So if I have 20 object stored in a vector and I delete the first, operator= is called 19 times!!!
«_Superman_» I love work. It gives me something to do between weekends.
-
Thanks. That is new information. So if I have 20 object stored in a vector and I delete the first, operator= is called 19 times!!!
«_Superman_» I love work. It gives me something to do between weekends.
Yep - that's why rvalue references[^] are being introduced in C++0x - they allow the introduction of 'move semantics', which allows the elimination of unnecessary copies like that.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Yep - that's why rvalue references[^] are being introduced in C++0x - they allow the introduction of 'move semantics', which allows the elimination of unnecessary copies like that.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
I had read about rvalue references and I'm able to admire it more now. Thanks :thumbsup:
«_Superman_» I love work. It gives me something to do between weekends.