c++ pointer management with local variables - c++

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

Related

Can you initialise a pointer and the corresponding object in one line in c++?

class test {
public:
int& n;
test(int& n) : n(n) {}
};
int main() {
test* ptr = ptr(3); // something like this and 3
// should be a variable as pointed out in the comments
}
Can you initialise a pointer and the object that it points to in one line?
Yes.
class test {
public:
int& n;
test(int& n) : n(n) {}
};
int main() {
int value = 3;
test obj(value), *ptr = &obj;
}
Note that int& n cannot accept literal like 3.
Another choice is using new to create an object on the heap.
class test {
public:
int& n;
test(int& n) : n(n) {}
};
int main() {
int value = 3;
test *ptr = new test(value); // create an object
delete ptr; // delete the object
}

Address Sanitizer : heap use after free crash when iterating through map of shared_ptr and coming out of scope

I am trying to create a map containing shared_ptr as values.In the function deleteB, I iterate through the map looking for a particular key value, when found, I erase the particular key, value pair and break out of the for loop, but as soon I come out of the deleteB function, the program crashes.I used address sanitizer and it shows heap use after free error.Not sure, where exactly this crash is happening.
struct MyObj{
int val;
void* ctx;
};
class A{
private:
MyObj obj;
int countVal;
public:
A(int value){
countVal = value;
obj = (MyObj){countVal, this};
}
~A(){}
MyObj getObj(){
return obj;
}
};
class B{
private:
int count = 0;
map<uint32_t, shared_ptr<A>> mB;
public:
void createB(MyObj &obj, int &getCount){
++count;
mB[count] = make_shared<A>(count);
obj = mB[count]->getObj();
getCount = count;
}
void deleteB(int Val){
if(!mB.empty()){
for(auto &a : mB){
if(a.first == Val){
mB.erase(a.first);
break;
}
}
}
}
};
int main(){
B b;
MyObj objVal;
int count = 0;
b.createB(objVal, count);
b.deleteB(count);
return 0;
}

Wrapping array of C objects into C++ class

I have C library with such API:
extern "C" {
typedef struct Opaque Opaque;
Opaque *foo_new();
void foo_delete(Opaque *);
int foo_f(Opaque *, int);
}
To simplify it's usage I wrap it in such way:
class Foo final {
public:
Foo() { self_ = foo_new(); }
~Foo() { foo_delete(self_); }
//code for copy/move constructor and operator=
int f(int a) { return foo_f(self_, a); }
private:
Opaque *self_;
};
All great, but then I have to wrap array of this opaque objects:
extern "C" {
typedef struct OpaqueArray OpaqueArray;
OpaqueArray *calc_foo_array();
void foo_array_delete(OpaqueArray *);
Opaque *foo_array_elem(OpaqueArray *, size_t i);
}
So I need implement class FooArray:
class FooArray final {
public:
??? operator[](const size_t i) {
auto obj = foo_array_elem(self_, i);
???
}
private:
OpaqueArray *self_;
};
But what should I return as result of operator[]?
I can create Foo from Opaque *, but then Foo::~Foo() is free part of array,
what is wrong. I can create FooRef that would be exactly the same as Foo,
but do not call foo_delete, but actually I have several such C classes,
and I prefer do not create so many code duplicates.
May be I can somehow use reinterpret_cast, because of sizeof(Foo) = sizeof(Opaque *) and return Foo & from operator[], but Foo & actually is Opaque **,
so I need somewhere hold Opaque to make it address stable.
May be there is some standard solution for such kind of problem?
You could modify your Foo class so that it can hold a pointer that it doesn't own.
class Foo
{
public:
Foo()
{
self_ = foo_new();
m_owned = true;
}
Foo(Opaque *pOpaque)
{
self_ = foo_new();
m_owned = false;
}
~Foo()
{
if (m_owned) foo_delete(self_);
}
//code for copy/move constructor and operator=
int f(int a) { return foo_f(self_, a); }
private:
bool m_owned;
Opaque *self_;
};
class FooArray
{
public:
Foo operator[](const size_t i)
{
return Foo(foo_array_elem(self_, i));
}
private:
OpaqueArray *self_;
};
I'd do it using proposed by You FooRef but a bit differently:
class FooRef {
public:
FooRef (Opaque *o) { self_ = o; }
int f(int a) { return foo_f(self_, a); }
protected:
Opaque *self_;
};
class Foo : public FooRef {
public:
Foo() { self_ = foo_new(); }
//code for copy/move constructor and operator=
~Foo () { foo_delete(self_); }
};
This solution avoids code duplication and allows you to safely return Foo from array. And by the way you got mechanism to simply create FooRef from Foo. Now you can do just:
class FooArray final {
public:
FooRef operator[](const size_t i) {
return FooRef(foo_array_elem(self_, i));
}
private:
OpaqueArray *self_;
};
I think that this should do the trick in elegant way.

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.

put pointer in std::vector & memory leak

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/