First time posting on here, and I'm not a CS guy, so please bear with me. I have a good sized, code, so I will post a bare-bones version of my problem below and then explain it.
#include <vector>
#include <memory>
class A{
public:
A(){};
double dbl[20];
};
typedef std::shared_ptr<A> A_ptr;
class B{
public:
const std::vector<A_ptr> createAVector(){
std::vector<A_ptr> vec;
for(int i=0; i<4; i++){
vec.push_back(A_ptr( new A() ));
}
return vec;
}
};
int myfunc(){
// Do Stuff...
std::vector<A_ptr> globvec;
B b;
for(int i=0; i<1e6; i++){
const std::vector<A_ptr> locvec = b.createAVector();
for(int i=0; i<locvec.size(); i++) globvec.push_back(locvec[i]);
}
globvec.clear();
globvec.shrink_to_fit();
// Do more stuff...
return 1;
}
int main(){
myfunc();
for(auto i=0; i<3; i++){
myfunc();
}
return 1;
}
Edit: I modified the code so it actually compiles.
So, basically I have two classes. Class A stores the actual data. Class B, among other things, creats a vector of std::shared_ptrs to A and returns it. I then assemble these local vectors into a large global vector in a function called myfunc. To test that memory is freed when I want to shrink the size of globA, I call globA.clear() and globA.shrink_to_fit().
The problem is that calling clear() and shrink_to_fit() does not free the memory of all the A's created.
Am I doing something obviously wrong here? Any idea what might be going on?
Any help would be greatly appreciated.
Thanks!
John
Your code is fine. You can essentially 'prove' that you are not leaking A objects with this... (I also had to reduce the number of iterations from 1e6 to get any reasonable runtime).
There are more sophisticated tools for finding memory leaks. I know for Linux we use Valgrind. I don't know what the Windows equivalent is however.
class A{
public:
A() { std::cout << "Created A " << ++num_instances << std::endl;}
~A() { std::cout << "Destroyed A " << --num_instances << std::endl;}
static int num_instances; // So not thread-safe
double dbl[20];
};
int A::num_instances = 0;
Related
If I have a class with members like this:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?
EDIT:
The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.
You need to implement the copy constructor, copy assignment and destructor.
Additionally, consider changing your vector declaration from
std::vector<MyStruct*> my_vector;
to
std::vector<std::unique_ptr<MyStruct>> my_vector;
so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.
No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:
Store MyStruct by value.
Store std::unique_ptr<MyStruct>.
Store std::shared_ptr<MyStruct>.
Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.
I have this class
class TestClass
{
public:
int* tab;
};
int main()
{
TestClass a;
a.tab[0]=8;
a.tab[1]=5;
TestClass b;
memcpy(b.tab,a.tab,sizeof(int)*2);
cout << b.tab[0] << endl;
return 0;
}
and I want to copy tab from a to b tab. But this code doesn't work.
I tried to copy tab to dynamic array and it worked.
TestClass a;
a.tab[0]=8;
a.tab[1]=5;
int* b=new int[2];
memcpy(b,a.tab,sizeof(int)*2);
cout << b[0] << endl;
Can someone explain why first code doesn't work but second works?
You're causing undefined behavior by trying to use the subscript operator with an uninitialized pointer. Instead of doing any of these, use std::vector or std::array, depending on what you are trying to achieve:
#include <iostream>
#include <vector>
class TestClass
{
public:
std::vector<int> tab;
};
int main()
{
TestClass a{ { 8, 5 } };
TestClass b{ a };
std::cout << b.tab[0] << '\n';
}
This keeps it simple and maintainable. STL containers have more friendly value semantics and they are in general easier to use, harder to abuse.
I try to create a vector with a pointer (so that everything is stored in/on the heap). I then want to fill the vector with an array of a class. I am thinking about accessing the class by class[i].member... Sadly, it does not work.
If I try this without a vector it works, like in:
tClass *MyClass = new tClass[5]
I am trying this without a specific purpose and only to understand C++ better. Can anyone have a look where I am wrong? Thanks!
Here is the code:
#include "iostream"
#include "vector"
using namespace std;
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){cout << "New" << endl;};
~tClass(){}; //do I need to make a delete here?
int main ()
{
vector<tClass> *MyClass[5];
MyClass = new vector<tClass>[5];
cout << MyClass[3].y << endl;
delete[] MyClass;
}
as others have suggested if you want just a vector of tClass you would do the following
vector<tClass> vectorName (5);
and access it like so
vectorName[3].y;
however if you wanted a vector of tClass pointers you would initialise and acess it like this
vector<tClass*> vectorName(5);
vectorName[3]->y;
edit
this might help you a bit more, this is your code, with comment to help you understand what is going wrong
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){ cout << "New" << endl; };
~tClass(){}; //do I need to make a delete here? //no you dont need to make a delete here as this class contains no "news"
int main()
{
vector<tClass> *MyClass[5]; //use () to give a vector an initial size, [] is only to access a member
//also to have a vector holding pointers, the asterisk needs to be after tClass not before the vector name
MyClass = new vector<tClass>[5];
cout << MyClass[3].y << endl; //discused above
delete[] MyClass; //only needed if a new is used, however you dont need one here, as it will just go out of scope
}
here is you code, but fixed to compile and run with the use of pointers
#include <iostream>
#include <vector>
using namespace std;
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){ cout << "New" << endl; };
};
int main()
{
vector<tClass*> MyClass(5);
cout << MyClass[3]->y << endl;
}
note though that this will give an error as the vector of class pointers are not pointing to any class
I have the next classes:
class A {
};
class B : public A {
int num;
};
in my main I have:
int main() {
A* vec; // A is a class with pure virtual functions
vec = new B[2]; // want to create a vector of B
}
vec[0] is defined correctly, but vec[1] is NULL. why didn't it allocate me a fit memory?
I don't want to change the lines of the main. just make it working.
(I know I can change the main into: B* vec = new B[2] but I don't want)
any help appreciated!
You cannot treat arrays polymorphically, the C++ language does not support it. The expression vec[x] uses pointer arithmetic to determine the location of the element. If you are accessing it through a base class pointer it will not work if the size of the objects vary in any way.
For example, you have base class that is 4 bytes in size and the subclass is 8 bytes in size.
base *a = new child[4];
When you access a[1] the compiler calculates the offset using the size of the base class. In this case the offset is 4 bytes which ends up pointing to the middle of the first element.
I recommend using a std::vector or std::array of pointers with an appropriate smart pointer.
// For arrays that needs to be resized (requires delete for each new)
std::vector<A*> vec(5, NULL);
for(int i = 0; i < vec.size(); i++)
{
vec[i] = new B();
}
// for arrays that are fixed in size (requires delete for each new)
std::array<A*, 5> vec;
for(int i = 0; i < vec.size(); i++)
{
vec[i] = new B();
}
// for arrays that are fixed in size with smart pointers
// no delete needed
std::array<std::unique_ptr<A>, 5> vec;
for(int i = 0; i < vec.size(); i++)
{
vec[i].reset(new B());
}
if you would like it to be polymorphic just create an array of pointers
new A*[array_size]
This code snippet illustrates the problem you are having.
#include <iostream>
using namespace std;
class A {
};
class B : public A {
int num;
};
int main() {
A* vec; // A is a class with pure virtual functions
vec = new B[2]; // want to create a vector of B
cout << sizeof(vec) << endl;
cout << sizeof(*vec) << endl;
cout << sizeof(vec[2]) << endl;
cout << sizeof(new B()) << endl;
}
In pointer arrithmetic, the size of the type of the pointer you allocated is what is used for incrementing, not the size of the true type of the object it is pointing to. More simply, the language does not support polymorphic arrays. This is simply an explanation of why.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is The Rule of Three?
I have the a problem of the double freeing of memory in the following program.
The debugger shows that the issue is in the push_back() function.
Class A:
class A {
public:
A(int x);
int x;
};
A::A(int x) {
this->x = x;
}
Class B:
class B {
public:
B(int x);
~B();
A* a;
};
B::B(int x) {
this->a = new A(x);
}
B::~B() {
delete a;
}
Main function:
int main() {
vector<B> vec;
for(int i = 0; i < 10; i++) {
vec.push_back(B(i)); <------------ Issue is here
}
cout << "adding complete" << endl;
for(int i = 0; i < 10; i++) {
cout << "x = " << (vec[i].a)->x << endl;
}
return 0;
}
What is wrong in this code?
EDIT: Error double free or memory corruption
You forgot to define a copy constructor and copy assignment operator, so your wrapped object is being deleted by some B.... then again when some copy of B goes out of scope.
In this case it's the B(i) temporary on the line you've identified, as well as an implementation-defined number of copies within the vector.
Abide by the rule of three.
The problem in your code is due to the fact that "plain" C/C++ pointers have no concept of ownership. When a pointer gets copied, both copies* "think" that they own the data, leading to double-deletion.
In recognition of this fact, the designers of the C++ standard library introduced a unique_ptr<T> class that helps you address problems like that.
* One copy of the pointer is in the instance of B passed to push_back; the other copy of the pointer is in the instance entered into the vector.
Heed the Rule of Three
Everyone else has already harped on this so I won't dive further.
To address the usage you are apparently trying to accomplish (and conform to the Rule of Three in the process of elimination), try the following. While everyone is absolutely correct about proper management of ownership of dynamic members, your specific sample can easily be made to avoid their use entirely.
Class A
class A {
public:
A(int x);
int x;
};
A::A(int x)
: x(x)
{
}
Class B
class B {
public:
B(int x);
A a;
};
B::B(int x)
: a(x)
{
}
Main Program
int main() {
vector<B> vec;
for(int i = 0; i < 10; i++) {
vec.push_back(B(i));
}
cout << "adding complete" << endl;
for(int i = 0; i < 10; i++) {
cout << "x = " << vec[i].a.x << endl;
}
return 0;
}
Bottom Line
Don't use dynamic allocation unless you have a good reason to, and it is lifetime-guarded by contained variables such as smart pointers or classes that vigorously practice the Rule of Three.