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
}
};
Related
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 have a class storing an multidimensional array as member.
struct Structure
{
Structure()
{
memset(Data, 0, sizeof Data);
}
int Number;
int Data[32][32][32];
}
When I write a function returning an object of this Structure, are all the bytes if the Data member copied or is just a reference passed?
Structure Create(int Parameter)
{
Structure structure;
// modify structure based on parameter
// ...
return structure;
}
If that results in copying the whole block of data, how can I do better? And what would it change to allocate the object on the heap like Structure *structure = new Structure(); and returning that pointer?
When you return the object by value, the actual data (323 ints) will be copied. It's possible the compiler will optimise away the copy (so called "copy elision"), but that is never guaranteed.
If you allocate the object dynamically and return a pointer to it, there will be no copying, of course. If you have access to C++11, consider returning a std::unique_ptr, so that ownership is clear and there's no chance of memory leaks.
In C++11, you could also "do better" by turning the member Data into a conainer (such as std::vector) which internally stores its data on the heap and has move semantics. This means that when returning from a function, the container will be moved instead of copied, and data will not be duplicated.
When you return an object by value the object will not actually be copied, instead your function will populate the object directly in the callers memory. It's as if you did the following:
Structure s;
Create(Parameter, &s);
Although a little better as the default constructor doesn't even get called. This is called "return value optimisation". Although it's not guarenteed by the standard, it is performed by all mainstream C++ compilers (clang, gcc, and Visual C++ all included).
If you want it on the heap then do this:
Structure * Create(int Parameter)
{
Structure * structure = new Structure();
return structure;
}
But it's better to use a smart pointer. If you're using c++11 you can use std::unique_ptr.
std::unique_ptr<Structure> Create(int Parameter)
{
auto structure = std::unique_ptr<Structure>(new Structure());
return structure;
}
You can have it behave however you want. If you define a function like this...
Structure* someFunction();
will return a pointer to a Structure object. This object must be allocated with new. For example defining the function like this:
Structure* someFunction() {
Structure* someNewStructure = new Structure();
return someNewStructure;
}
You have to remember that this element was created within this function, and the function is transferring "responsibility" for the destruction of this object on to the caller. It is usually best to avoid this, though with large data structures it can't be. Another way to handle this is to define a copy constructor in your class so that you can do it the way you referenced. Without defining this copy constructor if you did this:
Sturcture someFunction() {
Structure someResultStruct;
return someResultStruct;
}
When you call someFunction in this case, if your class contained dynamic elements, or other complex data types, they are not guaranteed to copy correctly on return, and you will get weird behavior... unless you define your own copy constructor.
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.
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;
}
}
I have a class that has a vector of objects. What do I need to do to return one of this objects and change it outside the class, keeping the changings? Is it possible to do with regular pointers? Is there a standard procedure? (And yes, my background is in Java.)
Your question is a bit vague, but here's an example:
class foo
{
public:
foo()
{
vec.resize(100);
}
// normally would be operator[]
int& get(size_t pIndex)
{ // the return type is a reference. think of it as an alias
return vec[pIndex]; // now the return value is an alias to this value
}
private:
std::vector<int> vec;
};
foo f;
f.get(10) = 5;
// f.get(10) returned an alias to f.vec[10], so this is equivalent to
// f.vec[10] = 5
The FAQ has a nice section on references.
Also, if you're new to C++ don't try learn with online resources. If you haven't got a book, you should, they're really the only good way to learn the language.
If the vector holds pointers to objects any change to one of the objects returned from the vector (or more accurately the object pointed) will affect the instance inside the vector as well.
If you have std::vector where A is your class, you could return a std::vector::iterator.
class A {
public: int a;
};
std::vector<A> v = ...;
std::vector<A>::iterator it = v.begin(); // access to the first element
it = v.begin() + 5; // access to the 5-th element (vector can do random access)
// 'it' can now be used elsewhere
it->a = 0; // changes are reflected in the object inside the vector
*it = A(); // changes the object hold by the vector
Beware, that iterators may be invalidated, if the vector changes!
You need to return either a reference or a pointer to the object.
type &getref(); // "type &" is a reference
type *getptr(); // "type *" is a pointer
The caller will then have access to the underlying object.
But you then need to make sure the object does not move (which can have if a vector has to grow). You may want to think about using a std::list instead.