There are legacy functions that need a dynamic array A**. For example,
A** array = new A*[100];
foo(array, 100);
...
void foo(A** a, int len) {
for(int i=0;i<len; ++i) {
a[i] = A::create(...);
}
}
I was wondering if I could use any "smart" pointers to manage this array.
I could use boost::scoped_array array. Its array.get() returns A**, and so it can work with legacy functions. But I think the destructor of array only free the top-level pointers, but not the second-level.
ptr_vector automatically deletes everything. But it does not have a way to return A**.
Do we have any other solutions?
If the API creates the objects using a call like A::create(...) which returns a pointer, then surely the API has a complementary call to destroy the objects such as A::destroy(ptr). In that case, the following custom deleter should be appropriate:
std::unique_ptr<A*, void(*)(A**)> array_ptr(
new A*[100],
[](A** ptr) {
for(std::size_t i = 0; i < 100; i++)
A::destroy(ptr[i]);
delete[] ptr;
}
);
foo(array_ptr.get(), 100);
EDIT I rewrote my answer, since the first version seemed to have been way off.
Related
I am trying to grasp the pointers in C++ but I can't find the answer to these questions.
If I was to have an ArrayList in Java and I wanted to add new Objects to it in a loop I would do something like:
ArrayList<MyObject> list = new ArrayList<MyObject> ();
for (int i = 0; i < otherList.length; i++) {
list.add(i, new MyObject(otherList.get(i)));
}
But let's say I wanted to do the same thing in C++ using vectors. I have found two methods:
vector<MyObject> vector;
for (auto i = otherVector.begin(); i != otherVector.end(); i++) {
// do this
vector[i - otherVector.begin()] = * new MyObject(*i);
// or this
MyObject newObj(*i);
vector[i - otherVector.begin()] = newObj;
}
What is the difference between those 2 methods and if I use the second one, do I need to manually delete the pointers from the list? If I were to use the second method with smart pointers, would they be automatically deleted by the gc when the vector was not used anymore?
The first method creates a memory leak. There's no saving it. Forget you ever heard of operator new.
if I use the second one, do I need to manually delete the pointers from the list?
There are no pointers in the list.
The second would work, and it would clean up after itself when vectorgoes out of scope. But do not do that either.
vector<MyObject> vector;
for (auto i = otherVector.begin(); i != otherVector.end(); i++) {
// do this
vector[i - otherVector.begin()] = * new MyObject(*i); // No, no, no, no.
// or this
MyObject newObj(*i);
vector[i - otherVector.begin()] = newObj; // Please don't.
}
But here's one way it should be done. No loop. (And don't name things "vector".)
std::vector<my_object> vec(other_vector);
If you're really into the brevity thing, do this:
auto vec{other_vector};
here is an example of a code hopefully will demonstrate my confusion
#define MAX_LENGTH 5
class Bar
{
private:
Foo *_myFooArray[MAX_LENGTH];
public:
Bar()
{
for (int i = 0; i < MAX_LENGTH; ++i)
{
_myFooArray[i] = new Foo(i);
}
}
};
Since I am not creating the array with new I don't think I can use delete[] but what if I want to delete the objects that are allocated dynamicly? do I iterate through the array and delete them one at a time? as such;
~Bar()
{
for (int i = 0; i < MAX_LENGTH; ++i)
{
delete _myFooArray[i];
}
}
I will probably hear some of you screaming at me Use Vectors!! I appreciate that. I just want to learn. Just for completeness, If for some reason I have to use the array as mentioned above, are there anything that I need to pay extra attention besides deleting the array correctly?
One of the rules in C++ when not using smart pointers is "every new needs a delete."
You must use the destructor from your question to avoid leaking memory. The array itself is not allocated using new so you do not need to delete it.
No, you do not delete [] the array. The array is part of your instance's data. The elements you allocate specifically are not, so you should delete them.
In my C++ code I have a class Object equipped with an id field of type int. Now I want to create a vector of pointers of type Object*. First I tried
vector<Object*> v;
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
but this failed because here the same address just repeats itself n times. If I used the new operator I would get what I want but I'd like to avoid dynamic memory allocation. Then I thought that what I need is somehow to declare n different pointers before the for loop. Straightforward way to this is to declare an array so I did this :
vector<Object*> v;
Object ar[n];
for(int i=0; i<n; i++) {
ar[i] = Object(i);
}
for(int i=0; i<n; i++) {
v.push_back(ar+i);
}
Is there still possibility to get a memory leak if I do it this way? Also going through an array declaration is a bit clumsy in my opinion. Are there any other ways to create vector of pointers but avoid manual memory management?
EDIT: Why do I want pointers instead of just plain objects?
Well I modified the original actual situation a bit because I thought in this way I can represent the question in the simplest possible form. Anyway I still think the question can be answered without knowing why I want a vector of pointers.
Actually I have
Class A {
protected:
vector<Superobject*> vec;
...
};
Class B: public A {...};
Class Superobject {
protected:
int id;
...
}
Class Object: public Superobject {...}
In derived class B I want to fill the member field vec with objects of type Object. If the superclass didn't use pointers I would have problems with object slicing. So in class B constructor I want to initialize vec as vector of pointers of type Object*.
EDIT2
Yes, it seems to me that dynamic allocation is the reasonable option and the idea to use an array is a bad idea. When the array goes out of scope, things will go wrong because the pointers in vector point to memory locations that don't necessarily contain the objects anymore.
In constructor for class B I had
B(int n) {
vector<Object*> vec;
Object ar[n];
for(int id=0; id<n; id++) {
ar[id] = Object(id);
}
for(int id=0; id<n; id++) {
v.push_back(ar+id);
}
}
This caused very strange behavior in objects of class B.
In this loop:
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
You are creating n times Object instance on stack. At every iteration there is created and removed element. You can simply avoid this using that:
for(int id=0; id<n; id++) {
Object* ob = new Object(id);
v.push_back(ob);
}
thanks that every new element exist on heap not on the stack. Try to add to in class Object constructor something like that:
std::cout<<"Object ctor()\n";
and the same in the destructor:
std::cout<<"Object dtor()\n";
If you dont want to create these objects with "new" try reason written by #woolstar
Your question about memory leaks makes me think you are worried about the lifecycle and cleanup of these objects. I originally proposed shared_ptr wrappers, but C++11 gave us unique_ptr, and C++14 filled in the missing make_unique. So with all that we can do:
vector<unique_ptr<SuperObject>> v ;
Which you create in place with the wonderfulness of perfect forwarding and variadic templates,
v.push_back( make_unique<Object>( ... ) ) ;
Yes you are going to have to live with some heap allocations, but everything will be cleaned up when v goes away.
Someone proposed a boost library, ptr_container, but that requires not only adding boost to your project, but educating all future readers what this ptr_container is and does.
No there is no memory leak in your version. When the program leaves your scope the vector as well the array are destroyed. To your second question: Why not simply store the objects directly in an vector?
vector<Object> v;
for(int i = 0; i < n; i++)
{
Object obj = Object(i);
v.push_back(obj);
}
I want to create a number of objects of a class, but this number won't be known until runtime. Intuition tells me that I should use the following loop to create my objects:
for (int count = 0; count < no_of_objects; count ++)
{
ClassName object_name[count]
}
This, however does not work as the compiler doesn't appear to like using variables as object names. Is there a way I can create these objects using a loop, or do I have to use some other method.
Please bear in mind that I have not been using C++ for long and have only recently been introduced to programming, so my knowledge of the language is somewhat limited - so far, the array is the only data structure I have been taught - no vectors, etc.
It's time to learn vectors:
std::vector<ClassName> objects (no_of_objects);
Now use objects[0] through objects[no_of_objects - 1]; note that objects.size() equals no_of_objects. When you're ready, look at vector's methods, etc., but for now, this plus knowing the header to include (<vector>) is enough to use objects as a dynamic array.
In C++ you will have to allocate this dynamically if you do not know the number of objects until runtime. You would need code similar to this:
ClassName* pmyClasses = new ClassName[no_of_objects];
This will allocate an array to hold your class objects, you then need to initialize them.
for (int i=0; i < no_of_objects; i++)
{
pmyClasses[i] = new ClassName();
}
You can then access them via the array indexer:
for (int i=0; i < no_of_objects; i++)
{
pmyClasses[i].SomeFunction();
}
An important thing to note here is that if you use new to allocate memory, then you need to use delete to deallocate it. Since this is an array declaration then you need to use the delete [] operator.
for (int i=0; i < no_of_objects; i++)
{
delete pmyClasses[i];
}
delete [] pmyClasses;
If you are using this inside or a class it would be important to have the delete in the destructor of the class:
class UsingMyClass
{
private:
ClassName* pmyClasses;
public:
UsingMyClass(int no_of_objects)
{
pmyClasses = new ClassName[no_of_objects];
for (int i=0; i < no_of_objects; i++)
{
pmyClasses[i] = new ClassName();
}
}
~UsingMyClass()
{
for (int i=0; i < no_of_objects; i++)
{
delete pmyClasses[i];
}
delete [] pmyClasses;
}
}
By doing this, when the UsingMyClass object goes out of scope (assuming it was not created via a call to new or malloc) then the array of ClassName objects will be cleaned up.
If your class has a default constructor (and you want to default construct the instances), you can use an array new i.e. new ClassName[some_number] - which is of type ClassName*).
If it doesn't have a default constructor, you can fool around with placement new, or use an array of pointers and new each one manually.
TO allocate the memory dynamically you have to use the new keyword
ClassName = new object_name[count];
and make sure to delaocate the memory after by using delete keyword
I have a vector with raw pointers (no, I cannot use smart pointers) and I want to add items to the list in a for loop. I've made a little trial project, and I wondered if this is considered good C++ code in terms of pointer management.
Please only consider raw pointer management, I am not interested in smart pointers for this particular problem I'm trying to solve.
A simple object:
class Request
{
public:
std::string name;
};
std::vector<Request*> requests;
for (int i = 0; i < 5; i++)
{
std::stringstream ss;
ss << "elemenent ";
ss << i;
std::string s = ss.str();
Request* req = new Request();
req->name = s;
requests.push_back(req);
}
EDIT:
So the problem I am trying to solve is adding the DOMNode* to a vector from this library.
I'm starting to get the feeling that trying to write a wrapper for the parts I need from this library for my project, is a bad idea. Or maybe the library is no good?
I haven't got it to work properly using smart_ptr, if anybody out there has, then I'd like to hear about it.
Well, this leaks memory, so it is bad. Can you use a Pointer Container?
The reason this code leaks is because you create objects on the heap using new, but you never call delete on them.
As for you comment, if you have an object that manually manages some resource, you need The Big Three.
I'll consider that you have a loop, at the end of the method, to call delete on each member of the vector.
There are still issues, specifically exception safety issues.
If anything throws between the creation of the Request and its registration in the vector, you've lost the memory. One solution is to temporarily use a scoped_ptr to hold on the memory, push_back with ptr.get() and then call the release method since now the memory is owned by the vector.
If anything throws between the point when you have created the items in the vector and the point you destroy them, you need to catch the exception, destroy the items, and then rethrow.
There might be others, but RAII has been invented for a reason, it's really difficult to do without (correctly...)
If you cannot use smart pointers, then use boost::ptr_vector.
Note that if you are using TinyXml, memory management in XmlNode is probably dictated by the library - recent history iirc is that many of your problems are associated with properly understanding the memory ownership and release paradigm for this library.
What memory management do I need to cleanup when using TinyXml for C++?
What is the best open XML parser for C++?
If you are not able (or allowed) to use smart pointers, probably you could make use of a simple memory manager like this:
template <class T>
class MemManager
{
public:
typedef std::vector<T*> Vec;
~MemManager ()
{
size_t sz = v_.size ();
for (size_t i = 0; i < sz; ++i)
delete v_[i];
}
T* pushNewObject ()
{
T* t = NULL;
try
{
t = new T;
if (t != NULL)
v_.push_back(t);
}
catch (std::bad_alloc& ex) { /* handle ex */ }
return t;
}
const Vec& objects() const { return v_; }
private:
Vec v_;
};
// test
{
MemManager<Request> mm;
for (int i = 0; i < 5; i++)
{
std::stringstream ss;
ss << "elemenent ";
ss << i;
std::string s = ss.str();
Request* req = mm.pushNewObject();
req->name = s;
}
} // all Request objects will be deleted here when
// the MemManager object goes out of scope.
A quick improvement could be to derive a class RequestVector from std::vector<Request*>, add a ClearRequests method (which deletes all the Request objects and clears the vector) and and make it's destructor call ClearRequests.
(Actually aggregating the vector in RequestVector could be a better choice, but a derived class is faster done).