Assume I have some object, such as:
std::map<int, std::vector<double> > some_map;
Simple question: is it more efficient to do the following
std::vector<double> vec = some_map[some_index];
or referencing it
std::vector<double>& vec = some_map[some_index];
Can anyone explain in short what typically happens behind the scenes here?
Thanks very much in advance!
The two have different semantics, and aren't interchangeable.
The first gives you a copy, which you can modify however you
wish, without changing anything in the map. The second gives
you a reference to the data element in the map; any
modifications modify the contents of the map. Also, although
probably not an issue, be aware that if the map is destructed
before the reference goes out of scope, the reference will
dangle.
With regards to performance, it depends on what's in the vector,
and what you do with it later; in most cases, the reference will
probably have better performance, but you shouldn't worry about
it until the profiler says you have to. (And if you do use the
reference, make it const, unless you really do want to be able
to modify the contents of the map.)
Creating a reference is more efficient, but you should note that these two statements are different in semantics and have different behaviors.
If you do
std::vector<double> vec = some_map[some_index];
The copy constructor of std::vector is called to copy the whole vector some_map[some_index] into vec. In this way, you get a fresh new vector vec. They are independent objects and any changes to vec does not affect the original map.
If you use
std::vector<double>& vec = some_map[some_index];
then vec refers directly to some_map[some_index] and copy is avoided. However, be aware that if you later change vec, the change will be reflected in both vec and some_map[some_index] since they refer to the same object. To prevent undesirable changes, it is safer to use a const reference:
const std::vector<double>& vec = some_map[some_index];
Referencing is much more efficient, both in terms of memory used and cpu cycles. Your first line of code makes a copy of the vector, which includes copying every item in the vector. In the second, you're simply referring to the existing vector. No copies are made.
Related
I have been overthinking (some may say underthinking, let's see what happens) the const-ness of STL containers and their elements.
I have been looking for a discussion of this, but the results have been surprisingly sparse. So I'm not necessarily looking for a definite answer here, I'd be just as happy with a discussion that gets the gears in my head moving again.
Let's say I have a class that keeps std::strings in a std::vector. My class is a dictionary that reads words from a dictionary file. They will never be changed. So it seems prudent to declare it as
std::vector<const std::string> m_myStrings;
However, I've read scattered comments that you shouldn't use const elements in a std::vector, since the elements need to be assignable.
Question:
Are there cases when const elements are used in std::vector (excluding hacks etc)?
Are const elements used in other containers? If so, which ones, and when?
I'm primarily talking about value types as elements here, not pointers.
My class is a dictionary that reads words from a dictionary file. They will never be changed.
Encapsulation can help here.
Have your class keep a vector<string>, but make it private.
Then add an accessor to your class that returns a const vector<string> &, and make the callers go through that.
The callers cannot change the vector, and operator [] on the vector will hand them const string &, which is exactly what you want.
No, for the reason you state.
In the context of std::vector, I don't think it makes sense to use a const qualifier with its template parameter because a std::vector is dynamic by nature and may be required to "move" in memory in order to "resize" itself.
In the C++03 standard, std::vector is guaranteed stored in contiguous memory. This almost requires that std::vector be implemented with some form of an array. But how can we create a dynamic size-changing array? We cannot simply just "append" memory to the end of it--that would either require an additional node (and a linked list) or actually physically putting our additional entries at the end of the array, which would be either out-of-bounds or require us to just reserve more memory in the first place.
Thus, I would assume that std::vector would need to allocate an additional array, copy or move its members over to the end array, and then delete the old one.
It is not guaranteed that a move or copy assignment for every template-able object for a std::vector would not change the underlying object being moved or copied--it is considered good form to do add the const qualifier, but it is not required. Therefore, we cannot allow a std::vector<const T>.
Related: How is C++ std::vector implemented?
consider using
std::vector<std::shared_ptr<const std::string>>
instead?
This is happening to me a lot during the making of this program and i thought it was better to ask you guys.
For example, if I have a loop that calls a specific structure of a vector, is it better to call the vector over and over like this:
FP_list[n].callsign=...
FP_list[n].de_airport=...
FP_list[n].ar_airport=...;
FP_list[n].aircraft_type=...
FP_list[n].trueairspeed=...
FP_list[n].FL_route.push_back(Aircraft.GetClearedAltitude());
FP_list[n].last_WP=...
FP_list[n].next_WP=...
...
Or to declare a temporary variable and use it from that point on like this:
FP temp=FP_list[n];
temp.callsign=...
...
temp.next_WP=...
Which one it better in terms of memory consumption and running time?
Thank you in advance
If FP_list is an std::vector or similar you can do:
FP& p = FP_list[n];
^^^ use a reference
p.callsign = ...;
p.de_airport = ...;
p.ar_airport = ...;
This code uses a reference to access the data. A reference gives you direct access to the element it refers. It works a bit like a pointer. Now you have to call operator[] only once, and your code is much more compact.
As noted in the comments, be careful that references might by invalidated if you make changes to the vector itself, e.g. adding or removing elements.
This assumes you actually want to change the contents stored in the vector. If you do not want to change them, you have to create a copy: FP p = FP_list[n];.
Efficiency is a trade-off. The way you wrote the code, it is making a copy of the structure. Depending on how expensive making that copy is, it may be far worse than the extra time to evaluate the index expression.
My conclusion: Write the code as cleanly as possible so it is obvious what it is doing, then let the optimizer in the compiler worry about efficiency. If performance does become an issue, then profile first so you can be sure you are hand-optimizing the right problem.
I have a memory leak in my application which I have been writing with Qt (C++) . And I suspect problem is with that line.
for(int i=0; i<DATA_LENGTH;i++){
cdata1->replace(i,data->at(i));
}
cdata1 is a QVector, data is a QList .
The reason I'm using replace(), I have constant length of data. And I didn't want to create a QVector each time. QVector is initialized on the object constructor with that line:
cdata1 = new QVector<double>(DATA_LENGTH,0);
Qt documentation says
Note that using non-const operators can cause QVector to do a deep
copy.
What I'm asking does replace() function causes a deep copy or how can I understand that?
Deep copy means the whole container, not the elements. As linked just after the sentence you quoted, QVector uses implicit sharing, also known as copy-on-write. read-only copies of the container are cheap, as the internals are shared, until one of the copy is modified:
QVector<A> vec1;
...
QVector<A> vec2 = vec1; //cheap, only copies a pointer internally. vec1 and vec2
int siz2 = vec2.size(); //cheap, doesn't modify vec2, vec1 and vec2 are still the same object, internally
vec2[0] = something; //potentially expensive: modifies vec2, thus vec2 "detaches" from vec1, getting its own copy of vec1's internal data, which is then modified by the assignment.
That's also the reason why creating containers on the heap is rather nonsensical (and unidiomatic) in almost all cases and you should create them on the stack instead.
Yes, it copies your double values. But I don't think double values can be subject to Memory Leaks unless you create them with new?
Anyway, dependent on your surrounding code you can maybe replace that whole block by using
cdata1 = data->toVector();
(see http://doc.qt.nokia.com/latest/qlist.html#toVector)
As an additional hint, you should start using more readable variable names than cdata1 or data. Your variables should describe what they are storing, e.g. if you have a list storing temperature data points it should be called something like temperatureDataPoints or temperatureDataPointList. It involves more typing than "data" of course, but you won't regret using more readable names if you look at your code in a year or so.
While there is quite a few questions about copy constructors/assignment operators on SO already, I did not find an answer that fit my problem.
I have a class like
class Foo
{
// ...
private:
std::vector<int> vec1;
std::vector<int> vec2;
boost::bimap<unsigned int, unsigned int> bimap;
// And a couple more
};
Now it seems that there is some quite excessive copying going on (based on profile data).. So my question is how to best tackle this?
Should I implement custom copy constructor/assignment operator and use swap? Or should I define my own swap method and use that (where appropriate) instead of assignment?
As I am not a c++ expert, examples that show how to properly handle this situation are greatly appreciated.
UPDATE: It appears I was not terribly clear.. Let me try to explain. The program is basically an on-the-fly breadth-first search program, and for each step taken I need to store metadata about the step (which is the Foo class).. Now the problem is that there is (usually) exponentially steps, so you can imagine a large number of these objects needs to be stored.. I do pass by (const) reference always as far as I know.. Each time I calculate a successor from a node in the graph I need to create and store ONE Foo object (however, some of the data members will be added to this one foo further on in the processing of this successor)..
My profile data shows roughly something like this (I don't have the actual numbers on this machine):
SearchStrategy::Search 13s
FooStore::Save 10s
So you can see I spend nearly as much time saving this meta data as I do searching through the graph.. Oh, and FooStore saves Foo in a google::sparse_hash_map<long long, Foo, boost::hash<long long> >.
Compiler is g++4.4 or g++4.5 (I'm not at my dev. machine, so I cannot check at the moment)..
UPDATE 2 I assign some of the members after construction to a Foo instance like
void SetVec1(const std::vector<int>& vec1) { this->vec1 = vec1; };
I guess tomorrow, I should change this to use the swap method, which should definitely improve this a bit..
I'm sorry if I'm not entirely clear about what semantics I'm trying to achieve, but the reason is that I am not quite sure.
Regards,
Morten
Everything depends on what copying this object means in your case :
it means copying it's whole value
it means the copied object will refer to the same content
If it's 1, then this class seem correct. You're not very clear about the operations that you say does make lot of copies so I'm assuming you try to copy the whole object.
If it's 2, then you need to use something like shared_ptr to share the containers between the objects. Just using shared_ptr instead of real objects as member will implicitely allow the buffers to be refered by both objects (the copy and the copied).
That's the easier way (using boost::shared_ptr or std::shared_ptr if you have a C++0x enabled compiler providing it).
There are harder ways but they will certainly become a problem later.
Of course, and everyone says this, don't optimize prematurely. Don't bother with this until and unless you prove a) that your program goes too slowly, and b) it would go faster if you didn't copy so much data.
If your program design requires you to hold multiple simultaneous copies of the data, there is nothing you can do. You just have to bite the bullet and copy the data. No, implementing a custom copy constructor and custom assignment operator won't make it go faster.
If your program doesn't require multiple simultaneous copies of this data, then you do have a couple of tricks to reduce the number of copies you perform.
Instrument your copy methods If it were me, the first thing I would do, even before trying to improve anything, is to count the number of times my copy methods were
invoked.
class Foo {
private:
static int numberOfConstructors;
static int numberofCopyConstructors;
static int numberofAssignments;
Foo() { ++numberOfConstructors; ...; }
Foo(const Foo& f) : vec1(f.vec1), vec2(f.vec2), bimap(f.bimap) {
++numberOfCopyConstructors;
...;
}
Foo& operator=(const Foo& f) {
++numberOfAssignments;
...;
}
};
Run your program with and without your improvements. Print out the value of those static members to see if your changes had any effect.
Avoid assignments in function calls by using references If you pass objects of type Foo to functions, consider if you can do it by reference. If you don't change the passed copy, passing it by const reference is a no-brainer.
// WAS:
extern SomeFuncton(Foo f);
// EASY change -- if this compiles, you know that it is correct
extern SomeFunction(const Foo& f);
// HARD change -- you have to examine your code to see if this is safe
extern SomeFunction(Foo& f);
Avoid copies by using Foo::swap If you use the copy methods (either explicitly or implicitly) a lot, consider whether the assigned-from item could give up its data, rather than copying it.
// Was:
vectorOfFoo.push_back(myFoo);
// maybe faster:
vectorOfFoo.push_back(Foo());
vectorOfFoo.back().swap(myFoo);
// Was:
newFoo = oldFoo;
// maybe faster
newfoo.swap(oldFoo);
Of course, this only works if myFoo and oldFoo no longer need access to their data. And, you have to implement Foo::swap
void Foo::swap(Foo& old) {
std::swap(this->vec1, old.vec1);
std::swap(this->vec2, old.vec2);
...
}
Whatever you do, measure your program before and after your change. Measure the number of times your copy methods are invoked, and the total time improvement in your program.
Your class doesn't seem that bad, but you do not show how you use it.
If there is lots of copying, then you need to pass objects of those class by reference (or if possible const reference).
If that class has to be copied, then you can not do anything.
If it's really a problem, you might consider implementing the pimpl idiom. But I doubt it's a problem, though I'd have to see your use of the class to be sure.
Copying of huge vectors unlikely can be cheap. The most promising way is to copy rarer. While it's quite easy (may be too easy) in C++ to invoke copy without intention, there are ways to avoid needless copying:
passing by const and non-const reference
move-constructors
smart pointers with ownership transfer
These techniques may leave only copies which are required by algorithm.
Sometimes it's possible to avoid even some of those copying. For example, if you need two objects where the second one is reversed copy of the first one, a wrapper object may be created which acts like reversed, but instead of storing entire copy has only a reference.
The obvious way to reduce copying is to use something like a shared_ptr. With multithreading, however, this cure can be worse than the disease -- incrementing and decrementing reference counts needs to be done atomically, which can be quite expensive. If, however, you typically end up modifying the copies and need each copy to act unique (i.e., modifying a copy doesn't affect the original) you can end up with worse performance still, paying for the atomic increment/decrement for reference counting, and still doing lots of copies anyway.
There are a couple of obvious ways to avoid that. One is to move unique objects instead of copying at all -- this is great if you can make it work. Another is to use non-atomic reference counting most of the time, and do deep copies only when moving data between threads.
There is no one answer that'a universal and really clean though.
I was wondering if there is any difference in performance when you compare/contrast
A) Allocating objects on the heap, putting pointers to those objects in a container, operating on the container elsewhere in the code
Ex:
std::list<SomeObject*> someList;
// Somewhere else in the code
SomeObject* foo = new SomeObject(param1, param2);
someList.push_back(foo);
// Somewhere else in the code
while (itr != someList.end())
{
(*itr)->DoStuff();
//...
}
B) Creating an object, putting it in a container, operating on that container elsewhere in the code
Ex:
std::list<SomeObject> someList;
// Somewhere else in the code
SomeObject newObject(param1, param2);
someList.push_back(newObject);
// Somewhere else in the code
while (itr != someList.end())
{
itr->DoStuff();
...
}
Assuming the pointers are all deallocated correctly and everything works fine, my question is...
If there is a difference, what would yield better performance, and how great would the difference be?
There is a performance hit when inserting objects instead of pointers to objects.
std::list as well as other std containers make a copy of the parameter that you store (for std::map both key and value is copied).
As your someList is a std::list the following line copies your object:
Foo foo;
someList.push_back(foo); // copy foo object
It will get copied again when you retrieve it from list. So you are making of copies of the whole object compared to making copies of pointer when using:
Foo * foo = new Foo();
someList.push_back(foo); // copy of foo*
You can double check by inserting print statements into Foo's constructor, destructor, copy constructor.
EDIT: As mentioned in comments, pop_front does not return anything. You usually get reference to front element with front then you pop_front to remove the element from list:
Foo * fooB = someList.front(); // copy of foo*
someList.pop_front();
OR
Foo fooB = someList.front(); // front() returns reference to element but if you
someList.pop_front(); // are going to pop it from list you need to keep a
// copy so Foo fooB = someList.front() makes a copy
Like most performance questions, this doesn't have one clear cut answer.
For one thing, it depends on what exactly you're doing with the list. Pointers might make it easier to do various operations (like sorting). That's because comparing pointers and swapping pointers is probably going to be faster than comparing/swapping SomeObject (of course, it depends on the implementation of SomeObject).
On the other hand, dynamic memory allocation tends to be worse than allocating on the stack. So, assuming you have enough memory on the stack for all the objects, that's another thing to consider.
In the end, I would personally recommend the best piece of advice I've ever gotten: It's pointless trying to guess what will perform better. Code it the way that makes the most sense (easiest to implement/maintain). If, and only if* you later discover there is a performance problem, run a profiler and figure out why. Chances are, most programs won't need all these optimizations, and this will turn out to be a moot point.
It depends how you use the list. Do you just fill it with stuff, and do lookups, or do you insert and remove data regularly. Lookups may be marginally faster without pointers, while adding and removing elements will be faster with pointers.
With objects it is going to be memberwise copy (thus new object creation and copy of members) assuming there aren't any copy constructors and = operator overloads. Therefore, using pointers is efficient std::auto_ptr or boost's smart pointers better, but that is beyond the scope of this question.
If you still have to use object syntax using reference.
Some additional things to consider (You have already been made aware of the copy semantics of STL containers):
Are your objects really smaller than pointers to them? This becomes more relevant if you use any kind of smart pointer as those have a tendency to be larger.
Copy operations are (often?) optimized to use memcpy() by the compiler. Especially this is probably not true for smart pointers.
Additional dereferencing caused by pointers
All the things I have mentioned are micro optimizations considerations and I'd discourage even thinking about them and go with them. On the other hand: A lot of my claims would need verification and would make for interesting test cases. Feel free to benchmark them.