I am reading a lot of different things on C++ optimization and I am getting quite mixed up. I would appreciate some help. Basically, I want to clear up what needs to be a pointer or not when I am passing vectors and structures as parameters or returning vectors and structures.
Say I have a Structure that contains 2 elements: an int and then a vector of integers. I will be creating this structure locally in a function, and then returning it. This function will be called multiple times and generate a new structure every time. I would like to keep the last structure created in a class member (lastStruct_ for example). So before returning the struct I could update lastStruct_ in some way.
Now, what would be the best way to do this, knowing that the vector in the structure can be quite large (would need to avoid copies). Does the vector in the struct need to be a pointer ? If I want to share lastStruct_ to other classes by creating a get_lastStruct() method, should I return a reference to lastStruct_, a pointer, or not care about that ? Should lastStruct_ be a shared pointer ?
This is quite confusing to me because apparently C++ knows how to avoid copying, but I also see a lot of people recommending the use of pointers while others say a pointer to a vector makes no sense at all.
struct MyStruct {
std::vector<int> pixels;
int foo;
}
class MyClass {
MyStruct lastStruct_;
public:
MyStruct create_struct();
MyStruct getLastStruct();
}
MyClass::create_struct()
{
MyStruct s = {std::vector<int>(100, 1), 1234};
lastStruct_ = s;
return s;
}
MyClass::getLastStruct()
{
return lastStruct_;
}
If the only copy you're trying to remove is the one that happen when you return it from your factory function, I'd say containing the vector directly will be faster all the time.
Why? Two things. Return Value Optimisation (RVO/NRVO) will remove any need for temporaries when returning. This is enough for almost all cases.
When return value optimisation don't apply, move semantics will. returning a named variable (eg: return my_struct;) will do implicit move in the case NRVO won't apply.
So why is it always faster than a shared pointer? Because when copying the shared pointer, you must dereference the control block to increase the owner count. And since it's an atomic operation, the incrementation is not free.
Also, using a shared pointer brings shared ownership and non-locality. If you were to use a shared pointer, use a pointer to const data to bring back value semantics.
Now that you added the code, it's much clearer what you're trying to do.
There's no way around the copy here. If you measure performance degradation, then containing a std::shared_ptr<const std::vector<int>> might be the solution, since you'll keep value semantic but avoid vector copy.
Related
Let's say my function:
vector<MyClass>* My_func(int a)
{
vector<MyClass>* ptr = new vector<MyClass>;
//...... Add a lot of elements to this vector, and let's say MyClass is also relatively big structure.
return ptr;
}
This method leaves responsibility for user to free the pointer.
Another method I can think of is just creating local variable in function and return the value:
vector<MyClass> My_func(int a)
{
vector<MyClass> vec;
//...... Add a lot of elements to this vector, and let's say MyClass is also relatively big structure.
return vec;
}
This one avoid the responsibility for user but may take a lot of space when return and copy the value.
Maybe smart pointer in C++ is a better choice but I am not sure. I did not use smart pointer before. What do people do when they come across this situation? What kind of return type will they choose?
Thanks ahead for your tips:-)
In most cases of this sort of construct, the compiler will do "Return Value Optimisation", which means that it's not actually copying the data structure being returned, but instead writing straight into one that lives on the place where it will be returned to.
So, you can safely do this without worrying about it being copied.
However, another method would be to not return a vector in the first, place, but request that the calling code pass one in:
So, something like:
void My_func(int a, vector<MyClass>& vec)
{
...
}
This is GUARANTEED to avoid copying.
In many situations return value optimizations easily can take care of the unnecessary copying. The question is: how are you planning to use this vector outside the function? If you have something like:
vector<MyClass> ret = My_func(a);
Then the optimizations can take care of the problem.
On the other hand, if you want to reuse an existing vector, you could pass a non-const reference to an existing vector, but there aren't many situations where this is needed or useful.
vector<MyClass> ret;
// do something with ret ...
My_func(a, ret);
Plus, this also changes the semantics of your function (e.g. you may need to clear() the vector).
Here is the internal structure of a vector
template <typename T>
class vector {
private:
size_t m_size;
size_t m_cap;
T * m_data;
public:
//methods push pop etc.
};
As you can the size of the vector (with 2 additional size_t data members) is not much larger than size of a pointer. There will be negligible performance benefit in passing a vector instead of pointer, infact using a pointer, accessing the vector will be slower as each time you will have to dereference the pointer. Generally, we don't create a pointer to a vector.
Also, never return a pointer to a local variable. The memory of the local variable will be wiped off once you return value & go out of the scope of the method. Ideally, you should create a vector in the calling function and pass a reference to the vector, when calling your method My_func.
I am looking for a way to insert multiple objects of type A inside a container object, without making copies of each A object during insertion. One way would be to pass the A objects by reference to the container, but, unfortunately, as far as I've read, the STL containers only accept passing objects by value for insertions (for many good reasons). Normally, this would not be a problem, but in my case, I DO NOT want the copy constructor to be called and the original object to get destroyed, because A is a wrapper for a C library, with some C-style pointers to structs inside, which will get deleted along with the original object...
I only require a container that can return one of it's objects, given a particular index, and store a certain number of items which is determined at runtime, so I thought that maybe I could write my own container class, but I have no idea how to do this properly.
Another approach would be to store pointers to A inside the container, but since I don't have a lot of knowledge on this subject, what would be a proper way to insert pointers to objects in an STL container? For example this:
std::vector<A *> myVector;
for (unsigned int i = 0; i < n; ++i)
{
A *myObj = new myObj();
myVector.pushBack(myObj);
}
might work, but I'm not sure how to handle it properly and how to dispose of it in a clean way. Should I rely solely on the destructor of the class which contains myVector as a member to dispose of it? What happens if this destructor throws an exception while deleting one of the contained objects?
Also, some people suggest using stuff like shared_ptr or auto_ptr or unique_ptr, but I am getting confused with so many options. Which one would be the best choice for my scenario?
You can use boost or std reference_wrapper.
#include <boost/ref.hpp>
#include <vector>
struct A {};
int main()
{
A a, b, c, d;
std::vector< boost::reference_wrapper<A> > v;
v.push_back(boost::ref(a)); v.push_back(boost::ref(b));
v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
return 0;
}
You need to be aware of object lifetimes when using
reference_wrapper to not get dangling references.
int main()
{
std::vector< boost::reference_wrapper<A> > v;
{
A a, b, c, d;
v.push_back(boost::ref(a)); v.push_back(boost::ref(b));
v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
// a, b, c, d get destroyed by the end of the scope
}
// now you have a vector full of dangling references, which is a very bad situation
return 0;
}
If you need to handle such situations you need a smart pointer.
Smart pointers are also an option but it is crucial to know which one to use. If your data is actually shared, use shared_ptr if the container owns the data use unique_ptr.
Anyway, I don't see what the wrapper part of A would change. If it contains pointers internally and obeys the rule of three, nothing can go wrong. The destructor will take care of cleaning up. This is the typical way to handle resources in C++: acquire them when your object is initialized, delete them when the lifetime of your object ends.
If you purely want to avoid the overhead of construction and deletion, you might want to use vector::emplace_back.
In C++11, you can construct container elements in place using emplace functions, avoiding the costs and hassle of managing a container of pointers to allocated objects:
std::vector<A> myVector;
for (unsigned int i = 0; i < n; ++i)
{
myVector.emplace_back();
}
If the objects' constructor takes arguments, then pass them to the emplace function, which will forward them.
However, objects can only be stored in a vector if they are either copyable or movable, since they have to be moved when the vector's storage is reallocated. You might consider making your objects movable, transferring ownership of the managed resources, or using a container like deque or list that doesn't move objects as it grows.
UPDATE: Since this won't work on your compiler, the best option is probably std::unique_ptr - that has no overhead compared to a normal pointer, will automatically delete the objects when erased from the vector, and allows you to move ownership out of the vector if you want.
If that's not available, then std::shared_ptr (or std::tr1::shared_ptr or boost::shared_ptr, if that's not available) will also give you automatic deletion, for a (probably small) cost in efficiency.
Whatever you do, don't try to store std::auto_ptr in a standard container. It's destructive copying behaviour makes it easy to accidentally delete the objects when you don't expect it.
If none of these are available, then use a pointer as in your example, and make sure you remember to delete the objects once you've finished with them.
I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.
I'm trying to learn C++, and trying to understand returning objects. I seem to see 2 ways of doing this, and need to understand what is the best practice.
Option 1:
QList<Weight *> ret;
Weight *weight = new Weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return &ret;
Option 2:
QList<Weight *> *ret = new QList();
Weight *weight = new Weight(cname, "Weight");
ret->append(weight);
ret->append(c);
return ret;
(of course, I may not understand this yet either).
Which way is considered best-practice, and should be followed?
Option 1 is defective. When you declare an object
QList<Weight *> ret;
it only lives in the local scope. It is destroyed when the function exits. However, you can make this work with
return ret; // no "&"
Now, although ret is destroyed, a copy is made first and passed back to the caller.
This is the generally preferred methodology. In fact, the copy-and-destroy operation (which accomplishes nothing, really) is usually elided, or optimized out and you get a fast, elegant program.
Option 2 works, but then you have a pointer to the heap. One way of looking at C++ is that the purpose of the language is to avoid manual memory management such as that. Sometimes you do want to manage objects on the heap, but option 1 still allows that:
QList<Weight *> *myList = new QList<Weight *>( getWeights() );
where getWeights is your example function. (In this case, you may have to define a copy constructor QList::QList( QList const & ), but like the previous example, it will probably not get called.)
Likewise, you probably should avoid having a list of pointers. The list should store the objects directly. Try using std::list… practice with the language features is more important than practice implementing data structures.
Use the option #1 with a slight change; instead of returning a reference to the locally created object, return its copy.
i.e. return ret;
Most C++ compilers perform Return value optimization (RVO) to optimize away the temporary object created to hold a function's return value.
In general, you should never return a reference or a pointer. Instead, return a copy of the object or return a smart pointer class which owns the object. In general, use static storage allocation unless the size varies at runtime or the lifetime of the object requires that it be allocated using dynamic storage allocation.
As has been pointed out, your example of returning by reference returns a reference to an object that no longer exists (since it has gone out of scope) and hence are invoking undefined behavior. This is the reason you should never return a reference. You should never return a raw pointer, because ownership is unclear.
It should also be noted that returning by value is incredibly cheap due to return-value optimization (RVO), and will soon be even cheaper due to the introduction of rvalue references.
passing & returning references invites responsibilty.! u need to take care that when you modify some values there are no side effects. same in the case of pointers. I reccomend you to retun objects. (BUT IT VERY-MUCH DEPENDS ON WHAT EXACTLY YOU WANT TO DO)
In ur Option 1, you return the address and Thats VERY bad as this could lead to undefined behaviour. (ret will be deallocated, but y'll access ret's address in the called function)
so use return ret;
It's generally bad practice to allocate memory that has to be freed elsewhere. That's one of the reasons we have C++ rather than just C. (But savvy programmers were writing object-oriented code in C long before the Age of Stroustrup.) Well-constructed objects have quick copy and assignment operators (sometimes using reference-counting), and they automatically free up the memory that they "own" when they are freed and their DTOR automatically is called. So you can toss them around cheerfully, rather than using pointers to them.
Therefore, depending on what you want to do, the best practice is very likely "none of the above." Whenever you are tempted to use "new" anywhere other than in a CTOR, think about it. Probably you don't want to use "new" at all. If you do, the resulting pointer should probably be wrapped in some kind of smart pointer. You can go for weeks and months without ever calling "new", because the "new" and "delete" are taken care of in standard classes or class templates like std::list and std::vector.
One exception is when you are using an old fashion library like OpenCV that sometimes requires that you create a new object, and hand off a pointer to it to the system, which takes ownership.
If QList and Weight are properly written to clean up after themselves in their DTORS, what you want is,
QList<Weight> ret();
Weight weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return ret;
As already mentioned, it's better to avoid allocating memory which must be deallocated elsewhere. This is what I prefer doing (...these days):
void someFunc(QList<Weight *>& list){
// ... other code
Weight *weight = new Weight(cname, "Weight");
list.append(weight);
list.append(c);
}
// ... later ...
QList<Weight *> list;
someFunc(list)
Even better -- avoid new completely and using std::vector:
void someFunc(std::vector<Weight>& list){
// ... other code
Weight weight(cname, "Weight");
list.push_back(weight);
list.push_back(c);
}
// ... later ...
std::vector<Weight> list;
someFunc(list);
You can always use a bool or enum if you want to return a status flag.
Based on experience, do not use plain pointers because you can easily forget to add proper destruction mechanisms.
If you want to avoid copying, you can go for implementing the Weight class with copy constructor and copy operator disabled:
class Weight {
protected:
std::string name;
std::string desc;
public:
Weight (std::string n, std::string d)
: name(n), desc(d) {
std::cout << "W c-tor\n";
}
~Weight (void) {
std::cout << "W d-tor\n";
}
// disable them to prevent copying
// and generate error when compiling
Weight(const Weight&);
void operator=(const Weight&);
};
Then, for the class implementing the container, use shared_ptr or unique_ptr to implement the data member:
template <typename T>
class QList {
protected:
std::vector<std::shared_ptr<T>> v;
public:
QList (void) {
std::cout << "Q c-tor\n";
}
~QList (void) {
std::cout << "Q d-tor\n";
}
// disable them to prevent copying
QList(const QList&);
void operator=(const QList&);
void append(T& t) {
v.push_back(std::shared_ptr<T>(&t));
}
};
Your function for adding an element would make use or Return Value Optimization and would not call the copy constructor (which is not defined):
QList<Weight> create (void) {
QList<Weight> ret;
Weight& weight = *(new Weight("cname", "Weight"));
ret.append(weight);
return ret;
}
On adding an element, the let the container take the ownership of the object, so do not deallocate it:
QList<Weight> ql = create();
ql.append(*(new Weight("aname", "Height")));
// this generates segmentation fault because
// the object would be deallocated twice
Weight w("aname", "Height");
ql.append(w);
Or, better, force the user to pass your QList implementation only smart pointers:
void append(std::shared_ptr<T> t) {
v.push_back(t);
}
And outside class QList you'll use it like:
Weight * pw = new Weight("aname", "Height");
ql.append(std::shared_ptr<Weight>(pw));
Using shared_ptr you could also 'take' objects from collection, make copies, remove from collection but use locally - behind the scenes it would be only the same only object.
All of these are valid answers, avoid Pointers, use copy constructors, etc. Unless you need to create a program that needs good performance, in my experience most of the performance related problems are with the copy constructors, and the overhead caused by them. (And smart pointers are not any better on this field, I'd to remove all my boost code and do the manual delete because it was taking too much milliseconds to do its job).
If you're creating a "simple" program (although "simple" means you should go with java or C#) then use copy constructors, avoid pointers and use smart pointers to deallocate the used memory, if you're creating a complex programs or you need a good performance, use pointers all over the place, and avoid copy constructors (if possible), just create your set of rules to delete pointers and use valgrind to detect memory leaks,
Maybe I will get some negative points, but I think you'll need to get the full picture to take your design choices.
I think that saying "if you're returning pointers your design is wrong" is little misleading. The output parameters tends to be confusing because it's not a natural choice for "returning" results.
I know this question is old, but I don't see any other argument pointing out the performance overhead of that design choices.
I was wondering if returning a list, instead of returning a pointer to one, was costly in term of performance because if I recall, a list doesn't have a lot of attributes (isn't it something like 3 pointers? One for the current position, one for the beginning and one for the end?).
If you return a std::list by value it won't just copy the list head, it will copy one list node per item in the list. So yes, for a large list it is costly.
If the list is built in the function which is returning it, then you might be able to benefit from the named return value optimisation, to avoid an unnecessary copy. That's specific to your compiler, though. It never applies if for example the list already existed before the function was called (for example if it's a member variable of an object).
A common idiom in C++, to avoid returning containers by value, is to take an output iterator as a parameter. So instead of:
std::list<int> getListOfInts() {
std::list<int> l;
for (int i = 0; i < 10; ++i) {
l.push_back(i);
}
return l;
}
You do:
template<typename OutputIterator>
void getInts(OutputIterator out) {
for (int i = 0; i < 10; ++i) {
*(out++) = i;
}
}
Then the caller does:
std::list<int> l;
getInts(std::back_inserter(l));
Often once the compiler has finished inlining and optimising, the code is more or less identical.
The advantage of this is that the caller isn't tied to a particular collection - for instance he can have the items added to a vector instead of a list if that is more useful for the particular circumstances. If he only needs to see each item once, instead of all of them together, then he can save memory by processing them in streaming mode using an output iterator of his own devising.
The disadvantages are the same as with any template code: the implementation must be available to the caller at compile time, and you can end up with a lot of "duplicate" object code for multiple instantiations of the template. Of course you can use the same pattern without using templates, by taking a function pointer (plus a user data pointer if desired) as a parameter and calling it once with each item, or by defining an IntVisitor abstract class, with a pure virtual member function, and having the caller provide an instance of it.
[Edit: T.E.D points out in a comment that another way to avoid the copy without using templates is for the caller to pass in a list by reference. This certainly works, it just gives the caller less flexibility than the template, and hence is not the idiom used by the STL. It's a good option if you don't want the "advantage of this" that I describe above. One of the original intentions behind the STL, though, is to separate "algorithms" (in this case whatever determines the values) from "containers" (in this case, the fact that the values happen to be stored in a list, as opposed to a vector or an array or a self-sorting set, or just printed out without storing them at all).]
It (as always) depends. The copy constructor may or may not be invoked by return in the following code.
std::list<int> foo() {
std::list<int> bar;
// ...
return bar;
};
It may not be invoked if the compiler applies return value optimization. If the copy-constructor is called, then it is probably more expensive relative to a pointer for larger lists, and if it isn't called, then it is faster to return the straight list (because it avoids a dynamic allocation)
Personally, I don't worry about it and return the straight list. Then, only when my profiler says this a problem do I consider optimizations.
If you return by value the copy constructor will be called and the items will be copied one by one. Sometimes you will be saved by the named value optimization as onebyone pointed out.
Your main options to ensure the copy will not take place are:
Pass in a list by reference to be filled in by the function. This way you tell the function where to put the data and no copy will need to be made because you put it in it's final place.
Allocate a list on the heap and return it. You should return it in a smart pointer like a std::auto_ptr or a boost::shared_ptr to ensure it gets delete and to be exception safe.
I believe, the copy-constructor is called.
It may be costly, in that it will copy every element in the list. More importantly, it has different behaviour: do you want a copy of the list or do you want a pointer to the original list?
You could write your own copy constructor so it does not copy.