You are partially replacing old code from the past. I'm replacing an existing pointer with a smart pointer for this operation, and I'm curious about deallocation. I replaced the code as below, will a leak occur?
std::vector<std::shared_ptr<Interface>> interface_list;
for (int i = 0 ; i < 5; ++i) {
Interface *buffer = CreateFactory(i);
if (buffer) interface_list.emplace_back(buffer);
}
...
for (std::shared_ptr<Interface> it: interface_list) {
it.reset();
}
//IS iT ok?
Assuming you fix the loop to call reset on the actual shared_ptrs instead of copies, the answer is "yes":
for (auto& it: interface_list) {
it.reset();
}
That leaves you with a list of dummy shared_ptr instances, of course.
You can also just clear the vector and have C++ reset the pointers for you:
interface_list.clear();
or just let interface_list go out of scope.
Related
Trying to understand the example for weak_ptr in Stroustrup's TCPL (pp 995, 4th Ed.). I understand the goal is to grab into a shared pointer (to a neighbor asteroid) when needed. The example code is:
void owner()
{
//...
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i) {
va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]))); // why?
}
}
A lot of stuff is going on in the marked line. I don't understand why reset is used, and why the constructor accepts a weak_ptr? Can someone explain that line in more details?
Interpreting the earmarked line,- Asteroid() constructor will accept a weak_ptr as a parameter and returns a shared_ptr. vector element va[i] relinquished any earlier ownership by calling reset before accepting the new shared_ptr.
The simplified code will look like so: Every new Asteroid will have a pointer to another neighbouring Asteroid, this pointer should be a weak_ptr to avoid cyclic reference due to interconnecting Asteroid pointers.
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i)
{
shared_ptr<Asteroid>sp = va[neighbor];
weak_ptr<Asteroid> wp = sp;
shared_ptr<Asteroid>sp2 = make_shared<Asteroid>(wp);
va[i].reset(sp2);
}
The reset fuction is equivalent to the assign operator (=), the difference is that the assign operator adds the shared_ptr object as a shared owner of the Asteroid object's assets, increasing their use_count, while the reset() function makes the shared_ptr acquires ownership of p with a use count of 1, making all the other owners release their ownership.
So, in this code, reset is being used to make va[i] the unique owner of the object at the time.
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.
i saw some code like below, but i didn't see any delete statement, is there any memory leak problem?
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
}
If you use vector<RStatus*>, then you have to use delete, otherwise you will have a memory leak.
However, if you use vector<RStatus>, then you don't have to use delete — this is recommended1.
1. If you want to use pointers, then the recommendation is that you should be using smart pointers such as std::unique_ptr, or std::shared_ptr.
Yes, you should free your memory allocated :
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
// free :
unsigned int size = rsVec.size();
for (unsigned int i = 0; i < size; i++ )
delete rsVec[i]; // delete because you used new
}
If you don't do that, all the memory will never be released at the vector destruction.
I would suggest you to use std::vector<RStatus> instead of std::vector<RStatus*>.
You may also used smart ptr. You can found some documentation about it here : http://www.cplusplus.com/reference/memory/shared_ptr/
EDIT: As suggested in comments, if an exception is thrown at rsVec.push_back(rs), the memory allocated will be lost, that's why smart pointers would be a better solution. Or again, use std::vector<RStatus> instead.
Yes, there is a memory leak: the pointer to the created structure is lost after the vector is destroyed, and the memory is never released.
Unless someone performs a delete for each element of rsVec before clearing or destroying the vector.
Yes, that code leaks the RStatus.
It also does nothing else: possibly the real code's vector gets passed to some function that takes posession of the vector's contents.
Tracking down memory leaks is generally not a local problem: every use of that pointer has to, in theory, be examine to figure out if it leaks. Techniques like 'if I allocate it, delete it' and RAII (including smart pointers) attempt to make it more local, so you can tell from an incomplete program if there is a leak.
use boost::shared_ptr if you don't want to bother yourself with a deletion of allocated objects.
http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<shared_ptr<RStatus> > rsVec;
shared_ptr<RStatus> rs = shared_ptr<RStatus>(); // empty shared_ptr
rs.reset(new RStatus()); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs); // shared_ptr is copied
}// vector is destroyed and shared_ptrs also
be careful however not to mixed up things using both shared_ptr and ordinary, raw pointers to avoid situation when shared_ptr tries to delete object which is already deleted
The proxy objects generated by gSoap indicate that I should use a vector of pointers:
class SOAP_CMAC ota__RoomStayTypeRoomRates
{
public:
std::vector<class ota__RoomRateType * >RoomRate;
//....
};
Rather than using:
vector.push_back(new Object());
and then having to delete the objects, I thought I might create a vector of objects and then use the address of those objects as they will be destroyed when the vector goes out of scope, thereby avoiding memory leaks:
OTARoomRates roomRates;
std::vector<ota__RoomRateType> rateObjectList;
rateObjectList.reserve(7);
for (int i = 0; i < 7; i++)
{
rateObjectList[i].RoomTypeCode = &roomTypeCode;
rateObjectList[i].RatePlanID = &ratePlanID;
//...
roomRates.RoomRate.push_back(&rateObjectList[i]);
}
I get a segfault. I suppose it's a bad idea. Can you explain why?
rateObjectList.reserve(7) doesn't actually allocate or construct any ota__RoomRateType objects; it simply requests that the vector expand its capacity enough to hold 7 objects.
Potentially, you wanted rateObjectList.resize(7). Or std::vector<ota__RoomRateType> rateObjectList(7); if you know the number at vector creation time.
Can you explain why?
Sure. If someone holds roomRates when rateObjectList destroyed then any attempt to use a pointer from roomRates can cause SEG_FAULT. That's a bad idea, anyway.
This is better in this case
vector.push_back(new Object());
Even better is to use smart-pointers, like boost::shared_ptr
I need to insert pointers of classes (inherited from QObject) into a QList. I know that the following syntax can be used:
.h
QList<MyObject*> list;
.cpp
list.append(new MyObject("first", 1));
list.append(new MyObject("second", 2));
...
and then free memory:
if(!list.isEmpty())
{
qDeleteAll(list);
list.clear();
}
This should be valid and does not cause any memory leaks (as far as I know). However, I need to initialize objects before adding them to the collection. Can the following piece of code cause some errors like memory leaks or dangling pointers (I'll use the same way to delete pointers as above)?
MyObject *obj;
for(i = 0; i < 5; i++)
{
obj = new MyObject();
if(!obj.Init(i, map.values(i)))
{
// handle error
}
else
{
list.append(obj);
}
}
Thanks.
if you take care of "obj" (the allocated but not initialized instance) in the "// handle error" case, your code is ok.
Use QSharedPointer instead.
QList<QSharedPointer<MyObject> > list;
To free memory you only have to do
if(!list.isEmpty())
{
list.clear();
}
To append to list
list.append(QSharedPointer<MyObject>(new MyObject("first", 1)));
list.append(QSharedPointer<MyObject>(new MyObject("second", 2)));
Use RAII (Resource Allocation Is Initialization). Initialize the object in constructor directly.
Then the code would look like:
for(i = 0; i < 5; i++)
{
list.append( new MyObject( i, map.values(i)));
// In case of initialization failure, throw exception from the constructor
}
You can use QScopedPointer..
From the Qt 4.6 documentation,
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction.
Managing heap allocated objects manually is hard and error prone, with the common result that code leaks memory and is hard to maintain. QScopedPointer is a small utility class that heavily simplifies this by assigning stack-based memory ownership to heap allocations, more generally called resource acquisition is initialization(RAII).
Hope it helps..
Edit:
For example,
You will use,
QScopedPointer<QWidget> p(new QWidget());
instead of
QWidget *p = new QWidget();
and add the QScopedPointer into your QList without worrying about memory leak and dangling pointers.