put pointer in std::vector & memory leak - c++

class A {
public:
void foo()
{
char *buf = new char[10];
vec.push_back(buf);
}
private:
vector<char *> vec;
};
int main()
{
A a;
a.foo();
a.foo();
}
In class A, foo() allocates some memory and the pointer is saved to vec. When main() finishes, a will desconstruct, and so will a.vec, but will the allocated memory be released?

The memory will not be released. For it to be released, you need to put it in either a unique_ptr or a shared_ptr.
class A {
public:
void foo()
{
unique_ptr<char[]> buf(new char[10]);
vec.push_back(buf);
}
private:
vector<unique_ptr<char[]>> vec;
};

Or you could make a destructor
~A()
{
for(unsigned int i =0; i < vec.size(); ++i)
delete [] vec[i];
}
EDIT
As pointed out you need to make copy and assignment also (if you intend to use them that is)
class A
{
public:
A& operator=(const A& other)
{
if(&other == this)
return *this;
DeepCopyFrom(other);
return *this;
}
A(const A& other)
{
DeepCopyFrom(other);
}
private:
void DeepCopyFrom(const A& other)
{
for(unsigned int i = 0; i < other.vec.size(); ++i)
{
char* buff = new char[strlen(other.vec[i])];
memcpy(buff, other.vec[i], strlen(other.vec[i]));
}
}
std::vector<char*> vec;
};
More on the subject of deep copying and why you need it here
http://www.learncpp.com/cpp-tutorial/912-shallow-vs-deep-copying/

Related

C++ pointer array moving

I am fairly new at the C/C++ pointer stuff, so I was wondering if this could cause any problems?
I got a class with a pointer array variable, which I would like to move along with the other variables in the move constructor. Can I just reasign its pointer, or is that a bad idea?
class C {
private:
char* a;
int size;
public:
C(int s)
{
size = s;
a = new char[s];
}
~C() noexcept
{
size = 0;
delete[] a;
}
C(const C& o): C(o.size)
{
std::copy(o.a, o.a + size, a);
}
C(C&& o) noexcept: size(o.size)
{
a = o.a;
o.a = nullptr;
}
C& operator=(const C& o)
{
if(this != &o)
{
char * l = new char[o.size];
size = o.size;
delete[] a;
a = l;
std::copy(o.a, o.a + size, a);
}
return *this;
}
C& operator=(C&& o) noexcept
{
if(this != &o)
{
delete[] a;
size = std::move(o.size);
a = o.a;
o.a = nullptr;
}
return *this;
}
};
Any feedback is welcome!
EDITS
Added move & assignment operator and copy constructor for complecity sake
Updated for full 'working' MVP
Why don't you use std::string and let the compiler do the work for you?
class C {
private:
std::string a;
public:
C() {}
}

Type Erasure with void pointer stored in vector of unique_ptr issues when copying

I've been banging my head on a crash that has to do with copy assignment of an object that holds a vector of unique_ptr that point to a class that hides std::vector data behind a void *. I have taken care of writing copy operator overloads so that the unique_ptr objects are copied correctly along their owning object.
Below is a minimal example of the issue. When executing the code, a crash relating to undefined memory happens when A is copied into B, the DataHolderImpl class is fed corrupted memory in it's set() method during the cloning of the object.
Any help would be really appreciated, this seems out of my depth and I'm not sure what to look for at this stage. Thanks !
#include <memory>
#include <vector>
#include <cstring>
class DataHolderBase {
public:
DataHolderBase() {};
virtual ~DataHolderBase() {};
virtual std::unique_ptr<DataHolderBase> clone() const = 0;
};
class DataHolderImpl : public DataHolderBase {
public:
DataHolderImpl() : DataHolderBase() {
m_data = new std::vector<float>;
}
~DataHolderImpl() {
delete reinterpret_cast<std::vector<float> *>(m_data);
}
std::unique_ptr<DataHolderBase> clone() const override {
DataHolderBase * copy = new DataHolderImpl(*this);
return std::unique_ptr<DataHolderBase>(copy);
}
void setVector(std::vector<float> const & data) {
if(m_data) {
delete reinterpret_cast<std::vector<float> *>(m_data);
}
m_data = (void *)malloc(sizeof(float) * data.size());
memcpy(m_data, data.data(), sizeof(float) * data.size());
}
void set(void * data) {
std::vector<float> * vec = reinterpret_cast<std::vector<float> *>(data);
setVector(*vec);
}
void* get() const {
return m_data;
}
DataHolderImpl(DataHolderImpl const & other) :
DataHolderBase(other),
m_data(nullptr)
{
set(other.get());
}
DataHolderImpl(DataHolderImpl && other) = default;
DataHolderImpl& operator=( DataHolderImpl const & other )
{
if(this != &other) {
set(other.get());
}
return *this;
};
DataHolderImpl& operator=( DataHolderImpl&& other ) = default;
private:
void * m_data;
};
class MyObject {
public:
MyObject() {
m_dataHolders.push_back(std::make_unique<DataHolderImpl>());
};
~MyObject() {};
MyObject(MyObject const & other)
{
m_dataHolders = std::vector<std::unique_ptr<DataHolderBase>>();
m_dataHolders.reserve(other.m_dataHolders.size());
for(auto const & dataHolder : other.m_dataHolders) {
m_dataHolders.push_back(dataHolder->clone());
}
}
MyObject(MyObject && other) = default;
MyObject& operator=( MyObject const & other )
{
if (this != &other)
{
m_dataHolders = std::vector<std::unique_ptr<DataHolderBase>>();
m_dataHolders.reserve(other.m_dataHolders.size());
for(auto const & dataHolder : other.m_dataHolders) {
m_dataHolders.push_back(dataHolder->clone());
}
}
return *this;
};
MyObject& operator=( MyObject&& other ) = default;
private:
std::vector<std::unique_ptr<DataHolderBase>> m_dataHolders;
};
class Test {
public:
Test() : m_A(), m_B()
{
m_B = m_A;
}
private:
MyObject m_A;
MyObject m_B;
};
int main(int argc, char * argv[]) {
auto A = Test();
auto B = A; // <- Crashes here.
return 0;
}

How can I fix this error in this case? "Invalid arguments ' Candidates are: void FreeMemory(std::vector<Element *,std::allocator<Element *>> &) '"?

How can I delete all the pointer in my vector before that I going to copy to my vector new pointers (in case of const object)?
class Element {
int val;
public:
Element(int val) :
val(val) {
}
};
class MyClass {
vector<Element*> v;
static void FreeMemory(vector<Element*>& vec) {
for (unsigned int i = 0; i < vec.size(); i++) {
delete vec[i];
}
}
public:
MyClass() = default;
MyClass(const MyClass& mc) {
//...
}
MyClass& operator=(const MyClass& mc) {
if (this == &mc) {
return *this;
}
//...
FreeMemory(mc.v); //**error** - how can I delete the memory of any Element?
//...
return *this;
}
// ....
// ....
};
binding 'const std::vector' to reference of type 'std::vector&' discards qualifiers
Can I fix it with smart_pointers?
Here is a sketch of a class owning a std::vector of Element objects managed by std::unique_ptr. Not fully worked out, but it might work as a starting point.
class Element {
int val;
public:
explicit Element(int val) : val(val) {}
virtual ~Element() = default;
/* Subclasses must implement this method: */
virtual std::unique_ptr<Element> clone() const = 0;
};
class ExclusivelyOwning {
private:
std::vector<std::unique_ptr<Element>> v;
public:
ExclusivelyOwning() = default;
ExclusivelyOwning(const ExclusivelyOwning& other) {
v.reserve(other.v.size());
for (const auto& element : other.v)
v.push_back(element->clone());
}
ExclusivelyOwning& operator=(const ExclusivelyOwning& rhs) {
/* Use copy-swap idiom, not shown here. */
return *this;
}
ExclusivelyOwning(ExclusivelyOwning&&) = default;
ExclusivelyOwning& operator = (ExclusivelyOwning&&) = default;
~ExclusivelyOwning() = default;
};
Note that copying an object with references to abstract classes (as Element in the code above) requires further techniques to render the copying meaningful. Here, I used a "virtual constructor" - the clone method.

copy constructor for const object

I have a following class foo
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
// Suppose I have made default and 1 parameter c'tor
foo(const foo &f)
{
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x; //doesn't work as I haven't initialized in member-initialization list, but how to write for loop in member initialization list ?
}
So How do I write for loop in member initialization list ?
You could just use a std::vector in this caseā€¦ anyways.
Typically, I will create a private static method which will perform the allocation and copy. Then the initialization list may be used:
static int* CloneInts(const foo& f) {
int* ints = new ...
...copy them from #a f.arr...
return ints;
}
Then your init-list would look like:
foo(const foo& f) : arr(CloneInts(f)), sz(f.sz) {
Have you tried constructing it with the copy constructor directly?
const foo y(x);
You should clarify your problem, because the one in the question doesn't actually exist.
The const foo y = x; line will compile and work with that copy constructor. A const object under construction isn't "const' until the constructor has completed. So the constructor body is permitted to modify the object even if the object being constructed is const.
Also note that the loop in the example isn't even modifying anything that's ever const - since the array is allocated dynamically, those array elements are modifiable even if the object itself isn't. For example, the arr pointer isn't modifiable after the ctor has completed, but arr[0] still is.
Try out the following to see both points in action:
#include <stdio.h>
#include <algorithm>
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
foo() : arr(0), sz(0) { puts("default ctor");}
foo(int x) : arr(0), sz(x) {
puts( "int ctor");
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=0;
}
foo(const foo &f)
{
puts("copy ctor");
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
~foo() {
delete [] arr;
}
foo& operator=(const foo& rhs) {
if (this != &rhs) {
foo tmp(rhs);
std::swap( arr, tmp.arr);
std::swap( sz, tmp.sz);
}
return *this;
}
void update() const {
for(int i = 0; i < sz; i++) {
arr[i] = arr[i] + 1;
}
}
void dump() const {
for(int i = 0; i < sz; i++) {
printf("%d ", arr[i]);
}
puts("");
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x;
y.dump();
y.update(); // can still modify the int array, even though `y` is const
y.dump();
}
I think you may be confusing constructing const objects with constructing objects that have const members since those members must be initialized in the initialization list.

c++ pointer management with local variables

I've got a method that creates some Foo and adds it to a vector of Foos. Foos are in charge of deleting their Bars during destruction. The Foo constructor takes a pointer of Bars and a size of them. When the function returns, the local Foo gets deleted and destroys its Bars, however I get a valid Foo object back.
How should I be handling this more correctly? Should I have Bars managed some other way? Should I have the constructor copy the array instead? I am potentially going to have hundreds of thousands of Bars.
Haven't tried to compile this, this is just an example of what is going on.
class Bar
{
public:
Bar(){}
~Bar(){}
int a;
int b;
int c;
};
class Foo
{
private:
Bar * myBars;
int size;
public:
Foo(Bar * myBars, int size)
{
this->myBars = myBars;
this->size = size;
}
Bar * getBars()
{
return myBars;
}
int getSize()
{
return size;
}
~Foo()
{
if(myBars != NULL)
{
if(size == 1)
{
delete myBars;
}
else if(size > 1)
{
delete [] myBars;
}
}
}
};
void doIt(std::vector<Foo> & foos)
{
Bar * myBars = new Bar[4];
//Pretend we initialize the Bars...
Foo foo(myBars);
foos.push_back(foo);
//local foo gets deleted
}
int main()
{
std::vector<Foo> foos;
doIt(foos);
Bar * myBars = foos[0].getBars();
int size = foos[0].getSize();
//Do something with myBars
return 0;
}
Why not use a std::vector for Bars:
class Foo
{
private:
vector<Bar> myBars;
public:
Foo(const vector<Bar>& bars) : myBars(bars) {}
vector<Bar>& getBars()
{
return myBars;
}
int getSize()
{
return myBars.size();
}
};
Similar to Bars, you can create Foo objects also on the heap to avoid destruction in doIt functon. If Foo object is dynamically allocated, it will not be destroyed upon the return of doIt() function.
You can clean up all Foo and Bar objects at the end like below(Working code)
#include <vector>
using namespace std;
class Bar
{
public:
Bar(){}
~Bar(){}
int a;
int b;
int c;
};
class Foo
{
private:
Bar * myBars;
int size;
public:
Foo(Bar * myBars, int size)
{
this->myBars = myBars;
this->size = size;
}
Bar * getBars()
{
return myBars;
}
int getSize()
{
return size;
}
~Foo()
{
if(myBars != NULL)
{
if(size == 1)
{
delete myBars;
}
else if(size > 1)
{
delete [] myBars;
}
}
}
};
void doIt(std::vector<Foo *> & foos)
{
Bar * myBars = new Bar[4];
//Pretend we initialize the Bars...
Foo *pFoo = new Foo(myBars, 4);
foos.push_back(pFoo);
}
int main()
{
std::vector<Foo *> foos;
doIt(foos);
Bar * myBars = foos[0]->getBars();
int size = foos[0]->getSize();
for(int i = 0;i < foos.size(); i++)
{
delete foos[i];
}
foos.clear();
return 0;
}
You don't show the copy constructor, and there is no appropriate default copy constructor.
You also don't have a default (no argument) constructor which is often needed by the stl containers.
When you push a Foo into the vector it is creating a new Foo as a copy.
Currently you are likely to be deleting the Bar pointer twice.
Native arrays should be avoided in use with non POD types - Bar[4] won't be running the constructor on Bar for each object. Prefer the use of Vector