My class has a pointer vector:
ptr_vector<Class> vec;
And in some "setup" method adds a few classes to the vector:
void setupOrSomething()
{
vec.push_back(new Class(...));
....
}
Now clients of this class may wish to add their Class objects to this classes list:
void addThingToMyList(Class *cPointer)
{
vec.push_back(cPointer);
}
And they may wish to remove them by passing the same pointer:
void removeThingFromMyList(Class *cPointer) { ... }
Now if I understand correctly, after reading this answer (https://stackoverflow.com/a/357043/48998), I need to implement that method as follows:
void removeThingFromMyList(Class *cPointer)
{
vec.release(std::find_if(vec.begin(),vec.end(),CheckPointerValue(cPointer)).release();
}
struct CheckPointerValue
{
CheckPointerValue(Class* c):cptr(c) {}
bool operator()(Class const& X) { return &X == cptr;}
private:
Class* cptr;
};
I understand I have to also call release() a second time on the auto_ptr that is returned from the ptr_vector.release().
Am I correct in assuming this will ensure that the caller of this method (RemoveThing...) will retain a valid reference to its Class object and that it will not be deleted? I simply want vec to gain a temporary ownership and then relinquish it.
Yes, they will retain a pointer to a valid instance. Of course they need to know that the pointer refers to a valid instance in the first place AND that a pointer to that instance is stored in the vector. If it's not, you will get undefined behavior and probably a seg fault.
Related
Suppose I have a method that defines a shared_ptr. After the method finishes, the shared_ptr will also be deleted. In the interim I have another member that uses that shared_ptr. So I would like to extend the lifetime of the shared_ptr past the initial method.
void initial_method(int input)
{
std::shared_ptr<int> a { std::make_shared<int>(input) };
some_delayed_method(a);
}
Is it possible to manually increase the reference count of a by one in this example?
some_delayed_method() is like a detachment and is referring to a at a time after the initial_method() has returned.
Since you can't call some_delayed_method without a shared_ptr to the object and any shared_ptr to the object extends its lifetime, there is nothing you need to do.
If some_delayed_method saves the pointer in some external data structure, and this pointer will later be used, you should use shared_ptr for that.
class X
{
public:
void initial_method(int input)
{
std::shared_ptr<int> a { std::make_shared<int>(input) };
some_delayed_method(a);
}
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a;
}
private:
std::shared_ptr<int> use_later;
}
This way, the reference count will be handled automatically.
You may insist on using a raw pointer to save the data for later:
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a.get();
}
...
int* use_later;
This is not a proper way to save the data. To make it work (or appear to work), you have to do some hack. For example, make another reference to the data, and leak it:
void some_delayed_method(const std::shared_ptr<int>& a)
{
use_later = a.get();
new std::shared_ptr<int>(a); // horrible hack; please never do it! but it works...
}
This hack leaks the allocated std::shared_ptr so it can never be deleted, thus its refcount is not decremented and the allocated int is leaked.
Given the following types
// interface and implementation used in one part of the codebase
struct Image
{
virtual std::vector<uint8_t>& GetData () = 0;
};
struct VecImage : public Image
{
std::vector<uint8_t> mData;
std::vector<uint8_t>& GetData () { return mData; }
};
// used in another part of the codebase
struct PtrImage
{
std::shared_ptr<uint8_t> mData;
PtrImage (std::shared_ptr<Image> pIm);
};
is the following constructor a sane and correct way to convert an Image to a PtrImage?
PtrImage::PtrImage (std::shared_ptr<Image> pIm)
{
struct im_deleter
{
std::shared_ptr<Image> keepAlive;
void operator () (uint8_t* ptr)
{
keepAlive.reset ();
}
};
mData = { &pIm->GetData()[0], im_deleter { pIm } };
}
PtrImage is used as a "value type", it is being passed around by value, while Image is passed around in shared_ptrs only.
is the following constructor a sane..
You extend lifetime of Image thanks to destructor, so data is still valid.
So you are correct on that point...
But, vector may reallocate, invalidating the buffer.
So resulting code is unsafe.
You could store std::shared_ptr<std::vector<uint8_t>> mData; to be safe.
.. and correct way
We have better/simpler with aliasing constructor of std::shared_ptr:
struct PtrImage
{
std::shared_ptr<std::vector<uint8_t>> mData;
PtrImage (std::shared_ptr<Image> pIm) : mData(pIm, &pIm->GetData()) {}
};
So ownership information PtrImage::mData is shared with pIm.
Note: I assumes that vector returned by GetData() has same (or longer) lifetime that Image (as for VecImage). if it is an unrelated vector (from other object), then you won't have solution.
As noted in comment, vector should not reallocate neither
Looks pretty dangerous to me:
std::shared_ptr<Image> i = std::make_shared<VecImage>(/* some data */);
PtrImage p(i); // has now stored a pointer to the vector's data
i->getData()->push_back(0); // repeat until re-allocation occurs!
What would p now hold? The shared pointer holds a pointer to the data that resided in the vector before re-allocation; but this data was replaced and got deleted. So you now have a dangling pointer stored in p (in the uint8_t pointer), using it (which will happen at latest when your smart pointer tries to delete its data) will result in undefined behaviour.
You should not even try to have a shared pointer guess whether it should delete its object or not. It you proceed that way, you will be caught at a time by a corner case or even if you managed to find all, by a new one created by an apparently unrelated change.
If you need to convert an Image to a PtrImage just say that you want to build a shared_ptr<T> from a T. There are 2 standard ways: a copy or a move, and in either the shared_ptr has ownership of its object.
In your example, as Image only returns a lvalue reference, you can only use a copy. You could have a move from a VecImage by taking ownership of its data member.
I am starting using c++11 features and I like to use smart pointers only to own the objects. Here is my class:
class MyClass {
public:
vector<MyObject*> get_objs() const;
private:
vector<unique_ptr<MyObject>> m_objs;
};
The semantics is that MyClass owns a serial of MyObject which are created through make_unique(). get_objs() returns a vector of raw pointers in order for various callers to update the objects. Because those callers do not own the objects, so the function does not return vector<unique_ptr>.
But this means I need to implement get_objs() like this:
vector<MyObjects*> MyClass::get_objs() const
{
vector<MyObjects*> ret;
for (auto obj : my_objs) {
ret.push_back(obj->get());
}
return ret;
}
My concern is get_objs() is called fairly often, each time there is an overhead to construct this raw pointer vector.
Is there something I could do here? If there is no c++11 tricks to save the overhead, should I just use type vector<MyObject*> for m_objs in the first place?
UPDATE 1
Jonathan Wakely's solution using operator[] improves mine so that caller can access individual object directly.
Is there any other solution? I do not mind go over all the places calling get_objs(), but like to see if there is even better solution.
Another note - I cannot use BOOST, just some restriction I have to live with.
For a start you can use ret.reserve(m_objs.size()) to pre-allocate the right number of elements.
Alternatively, don't return a vector for callers to iterate over directly, but expose a vector-like interface instead:
class MyClass {
public:
struct iterator;
iterator begin();
iterator end();
MyObject* operator[](size_t n) { return m_objs[n].get(); }
private:
vector<unique_ptr<MyObject>> m_objs;
};
This allows the callers to modify the objects directly, rather than getting a container of pointers.
class MyClass {
public:
std::vector<std::unique_ptr<MyObject>> const& get_objs() const {
return m_objs;
}
private:
std::vector<std::unique_ptr<MyObject>> m_objs;
};
a const std::unique_ptr<MyObject>& cannot steal ownership, and is not the same as a std::unique_ptr<const MyObject>. A const std::vector<std::unique_ptr<MyObject>>& can only grant const access to its data.
In c++20 I would instead do this:
class MyClass {
public:
std::span<std::unique_ptr<MyObject> const> get_objs() const {
return {m_objs.begin(), m_objs.end()};
}
private:
std::vector<std::unique_ptr<MyObject>> m_objs;
};
which hides the implementation detail of "I am storing it in a vector" while exposing "I am storing it contiguously".
Prior to c++20, I advise finding or writing your own span type if you have the budget. They are quite useful.
If you can use Boost, try indirect_iterator (http://www.boost.org/doc/libs/1_55_0b1/libs/iterator/doc/indirect_iterator.html). You need to define iterator, begin and end in your class:
typedef boost::indirect_iterator<vector<unique_ptr<MyObject>::iterator> iterator;
iterator begin() { return make_indirect_iterator(m_objs.begin()); }
Then your class exposes iterator, the value of which is reference (not pointer!) to MyObject. You can iterate and access the elements of the vector directly.
For the record, I think something like Jonathan Wakely's answer is the way to go. But since you asked for more possibilities, another one is to use shared_ptr instead of unique_ptr:
class MyClass {
public:
const vector<shared_ptr<MyObject>>& get_objs() const {
return m_objs;
}
private:
vector<shared_ptr<MyObject>> m_objs;
};
This improves the original code in two ways:
There is no longer any need to build up a new vector in get_objs; you can just return a reference to the one you have.
You no longer need to worry about wild pointers in the case where a caller keeps the return value alive longer than the object that returned it--shared_ptr ensures the pointed-to objects aren't deleted until all references have been released.
On another note, get_objs arguably should not be const. Calling code can't modify the vector itself, but it can modify the MyObjects it contains.
Another way is not to return any objects at all and encapsulate how you are storing the data (tell don't ask).
Usually when you get the items you end up iterating through them all, so it makes sense to wrap that up in the class and pass in a function you want your objects to pass through.
The non boost way will be something like
void MyClass::VisitItems(std::function<void, MyObject&> f)
{
for (auto obj : my_objs)
{
f(*obj);
}
}
let's say that i need to create some buffer or a vector of objects or whatever
and that data needs to be given to an object constructor...
is it common practice to be generate the data in a class function like this
class A
{
void gen()
{
vector<Data*> v;
obj= new Obj(&v);
}
}
...
class Obj
{
private:
vector<Data*> *data;
public:
Obj(vector<Data*> *v)
{
data=v;
}
}
good idea? bad idea?
the background question would be do i use pointers, references... as entry and output of my functions & constructors, when and for what reason...
thanks
In particular, this is a very bad idea:
{
vector<Data*> v;
obj= new Obj(&v); // 1: pass address of v
} // 2: v gets destroyed (obj will hold the address of
// an out-of-scope variable) and application will
// probably crash when it attempts to use it.
do i use pointers, references... as entry and output of my functions & constructors, when and for what reason...
That's a ... broad subject. In general, you should:
use objects directly, when declaring them in a scope (by value).
pass objects by const reference, when the function you pass them in just needs read-only access.
pass objects by non-const reference when the function alters the object
if you need an object outside of the scope you create it in, return by value if possible, otherwise use a pointer (see "avoiding raw pointers" below)
Avoiding raw pointers:
raw pointers (T*) should be:
replaced with std::unique_ptr when only one owner of the pointer will exists (when the pointer is used in one place)
replaced with std::shared_ptr when ownership is shared, there are multiple owners, or when there is no clear owner of the pointer.
replaced with std::vector when you need an arbitrary length array of values
replaced with std::array when you need an array of n values
the only places where you use raw pointers are:
when you are interested in the pointer values themselves (e.g. logging allocated addresses, tracking memory, writing an allocator or object pool, implementing an iterator type)
when you are interacting with legacy or the C library.
In your particular case:
class Obj
{
private:
vector<Data*> data; // store by value
public:
Obj(vector<Data*> v) // pass by value (creates a copy of the data)
: data{ std::move(v) } // move passed value into internal member
{
}
};
class A
{
Obj gen() // return obj by value
{
vector<Data*> v; // allocate by value
Obj obj{ std::move(v) }; // move v into obj
return obj; // return by value
}
};
I have C++ class as follows
class anotherClass;
class myClass {
private:
myClass() {}
~myClass() {}
typedef std::map<string, anotherClass* > stringToClass;
static stringToClass s_stringToClass;
public:
static anotherClass* getStringToclass(string name);
};
in above class for getStringToClass defintion is as follows
anotherClass* myClass::getStringToClass(string name) {
stringToClass::iterator iter;
iter = s_stringToClass.find(name);
if(iter == s_stringToClass.end()) {
typedef stringToClass::value_type stringToClassPair;
anotherClass* pothClass = new anotherClass();
s_stringToClass.insert(stringToClassPair(name, pothClass));
return pothClass;
}
else {
return iter->second;
}
}
now my question is we are allocating memory in static function as defined above. How can we delete memory? Can we delete memory in destructor, as destructor is not static?
Thanks for the help.
The collection will automatically clean up but the pointers inside it will not be, so you really have 2 options:
Used a collection of shared_ptr which will get cleaned up
Use a collection that stores raw pointers but cleans them up
There are classes of the latter type in boost but not sure they have one for maps and I would go for the former.
I would modify the structure too so that instead of using a static function and a static map, I would have a class with a function and a map, and have a static (singleton) instance of that class.
Your function may also be modified to return a shared_ptr but it could still return a regular pointer as the item will remain in the map forever and thus you do not need to worry about it becoming invalidated.
And as it can never be NULL you can even return a reference.
typedef std::map<string, boost::shared_ptr<anotherClass> > stringToClass;
anotherClass& myClass::getStringToClass(string const& name)
{
boost::shared_ptr<anotherClass> & value = s_stringToClass[name];
if( !value )
{
value.reset( new anotherClass );
}
return *value;
}
You might consider making it thread-safe too.
If you store it in a static variable, I guess you need them till the end of the execution of your process... If not, then you need to add a method to clean this static variable by deleting each element and call it when you don't need it anymore.
You should not do it in the destructor as the static variable is not linked to your class instances.
I'd use some kind of smart pointer such as the ones provided by Boost instead of raw pointers.
Yes, you can delete static variables in the destructor.
That being said, it's not a very good idea. What if you have two instances of your class, both using the static variable, and one gets destroyed? Its destructor would delete the memory, causing problems for the remaining instance of your class.
In addition to your odd usage of static members, it would be wiser to use smart pointers.
I think in your case, the destructor won't help, because there is no any object of MyClass.
I propose three ways
1. Don't store pointer, store the object itself.
2. Put the delete function into atexit; In your case
class MyClass
{
.....//Your already existing code
static void Destroy()
{
//iterate s_StringToClass and delete them
}
static void getStringToClass( string name )
{
struct DestroySetter
{
DestroySetter()
{
atexit( MyClass::Destroy );
}
};
static DestroySetter setter; //Setup the destoyer
//Your existing code here
}
3. Use smart pointer to manage the resource, shared_ptr is recommended.
Though I put a lot in second way, I suggest the 3rd way.
Problem one:
Functions should never return pointers (unless you really really really have too).
In this case you don't.
A returned pointer has no ownership semantics so it is not clear who the owner of the pointer is (if you don't know who owns the pointer then you don;t know who is reponsable for deleting it).
So either return a refernce or a smart pointer.
In this case a reference. As all the dynamically created objects are being maintained locally.
Since you are obviously new to this. Use a boost::shared_pointer. Technically this is probably not the best one for this situation, but it is the easiest one to just use when learning. I would have a look at the other smart pointers that are available and learn when it is appropriate to use each one.
class anotherClass;
class myClass
{
private:
myClass() {}
~myClass() {}
typedef boost::ptr_map<string, anotherClass > stringToClass;
// ^^^ Note: Not std:: you are not allowed to add class to std::
static stringToClass s_stringToClass;
// Ownership now maintained by the map automatically.
public:
// Return a reference.
// We retain ownership inside this class
static anotherClass& getStringToclass(string name);
};
Code:
anotherClass& myClass::getStringToClass(string name)
{
stringToClass::iterator iter;
iter = s_stringToClass.find(name);
if(iter == s_stringToClass.end())
{
s_stringToClass[name] = new anotherClass();
return s_stringToClass[name];
}
else
{
return iter->second;
}
}