Insert elements into std::map without extra copying - c++

Consider this program:
#include <map>
#include <string>
#define log magic_log_function // Please don't mind this.
//
// ADVENTURES OF PROGO THE C++ PROGRAM
//
class element;
typedef std::map<int, element> map_t;
class element {
public:
element(const std::string&);
element(const element&);
~element();
std::string name;
};
element::element(const std::string& arg)
: name(arg)
{
log("element ", arg, " constucted, ", this);
}
element::element(const element& other)
: name(other.name)
{
name += "-copy";
log("element ", name, " copied, ", this);
}
element::~element()
{
log("element ", name, " destructed, ", this);
}
int main(int argc, char **argv)
{
map_t map1; element b1("b1");
log(" > Done construction.");
log(" > Making map 1.");
map1.insert(std::pair<int, element>(1, b1));
log(" > Done making map 1.");
log(" > Before returning from main()");
}
It creates some objects on stack and inserts them into an std::map container, creating two extra temporary copies in the process:
element b1 constucted, 0x7fff228c6c60
> Done construction.
> Making map 1.
element b1-copy copied, 0x7fff228c6ca8
element b1-copy-copy copied, 0x7fff228c6c98
element b1-copy-copy-copy copied, 0x232d0c8
element b1-copy-copy destructed, 0x7fff228c6c98
element b1-copy destructed, 0x7fff228c6ca8
> Done making map 1.
> Before returning from main()
element b1 destructed, 0x7fff228c6c60
element b1-copy-copy-copy destructed, 0x232d0c8
We can get rid of one extra copy constructor call by changing the std::pair signature to std::pair<int, element&>, however, the second temporary is still created and immediately destroyed:
element b1 constucted, 0x7fff0fe75390
> Done construction.
> Making map 1.
element b1-copy copied, 0x7fff0fe753c8
element b1-copy-copy copied, 0x1bc4098
element b1-copy destructed, 0x7fff0fe753c8
> Done making map 1.
> Before returning from main()
element b1 destructed, 0x7fff0fe75390
element b1-copy-copy destructed, 0x1bc4098
Is there a way to make std::map just take an object on stack by reference and make a single internal copy of it?

This is one of the many use cases which motivated C++11's move functionality, supported by a host of new features, particularly rvalue references, and a variety of new standard library interfaces, including std::map::emplace, std::vector::emplace_back, etc.
If, for whatever reason, you cannot yet use C++11, you can at least console yourself with the thought that the problem has been recognized, and that a solution has been standardized and implemented, and that furthermore many of us are using it, some of us [1] in production-code. So, as the old joke has it, a solution exists and it's your call as to when you take it up.
Note that you don't have to use the emplace member function if your objects implement move constructors, which they may even do by default. This won't happen if the have explicit copy constructors, so your test above may produce observer effects (and indeed, it might also suppress compiler optimizations in the case of PODs, so even with C++03 you might not have the problem you think you do).
There are a variety of hacks available which kinda-sorta avoid copies with only "minor" source code alterations, but IMHO the best approach is to start moving towards C++11. Whatever you do, try to do it in a way that will make the inevitable migration less painful.
[Note 1]: Disclaimer: I no longer write production code, having more or less retired, so I'm not part of the "some of us" in that sentence.

Standard practice (with older C++ versions) where I've been is to use a Map of shared pointers.
Still creates a copy of the shared pointers, but that's usually much less onerous than copying large objects.

You can use emplace() :
The element is constructed in-place, i.e. no copy or move operations are performed. The constructor of the element type (value_type, that is, std::pair) is called with exactly the same arguments as supplied to the function

Well, if you dont have emplace, you can construct the element on the heap and pass pointers to map:
typedef std::map<int, element*> map_t;
...
printf(" > Making pair 1.\n");
std::pair<int, element*> pair(1, new element ("b1")) ;
printf(" > Making map 1.\n");
map1.insert(pair);
but then you are subject to memory-leaks if you dont take care when your map leaves scope...

Related

C++ class with container of pointers to internal data members: copying/assignment

Suppose I have a class Widget with a container data member d_members, and another container data member d_special_members containing pointers to distinguished elements of d_members. The special members are determined in the constructor:
#include <vector>
struct Widget
{
std::vector<int> d_members;
std::vector<int*> d_special_members;
Widget(std::vector<int> members) : d_members(members)
{
for (auto& member : d_members)
if (member % 2 == 0)
d_special_members.push_back(&member);
}
};
What is the best way to implement the copy constructor and operator=() for such a class?
The d_special_members in the copy should point to the copy of d_members.
Is it necessary to repeat the work that was done in the constructor? I hope this can be avoided.
I would probably like to use the copy-and-swap idiom.
I guess one could use indices instead of pointers, but in my actual use case d_members has a type like std::vector< std::pair<int, int> > (and d_special_members is still just std::vector<int*>, so it refers to elements of pairs), so this would not be very convenient.
Only the existing contents of d_members (as given at construction time) are modified by the class; there is never any reallocation (which would invalidate the pointers).
It should be possible to construct Widget objects with d_members of arbitrary size at runtime.
Note that the default assignment/copy just copies the pointers:
#include <iostream>
using namespace std;
int main()
{
Widget w1({ 1, 2, 3, 4, 5 });
cout << "First special member of w1: " << *w1.d_special_members[0] << "\n";
Widget w2 = w1;
*w2.d_special_members[0] = 3;
cout << "First special member of w1: " << *w1.d_special_members[0] << "\n";
}
yields
First special member of w1: 2
First special member of w1: 3
What you are asking for is an easy way to maintain associations as data is moved to new memory locations. Pointers are far from ideal for this, as you have discovered. What you should be looking for is something relative, like a pointer-to-member. That doesn't quite apply in this case, so I would go with the closest alternative I see: store indices into your sub-structures. So store an index into the vector and a flag indicating the first or second element of the pair (and so on, if your structure gets even more complex).
The other alternative I see is to traverse the data in the old object to figure out which element a given special pointer points to -- essentially computing the indices on the fly -- then find the corresponding element in the new object and take its address. (Maybe you could use a calculation to speed this up, but I'm not sure that would be portable.) If there is a lot of lookup and not much copying, this might be better for overall performance. However, I would rather maintain the code that stores indices.
The best way is to use indices. Honestly. It makes moves and copies just work; this is a very useful property because it's so easy to get silently wrong behavior with hand written copies when you add members. A private member function that converts an index into a reference/pointer does not seem very onerous.
That said, there may still be similar situations where indices aren't such a good option. If you, for example have a unordered_map instead of a vector, you could of course still store the keys rather than pointers to the values, but then you are going through an expensive hash.
If you really insist on using pointers rather that indices, I'd probably do this:
struct Widget
{
std::vector<int> d_members;
std::vector<int*> d_special_members;
Widget(std::vector<int> members) : d_members(members)
{
for (auto& member : d_members)
if (member % 2 == 0)
d_special_members.push_back(&member);
}
Widget(const Widget& other)
: d_members(other.d_members)
, d_special_members(new_special(other))
{}
Widget& operator=(const Widget& other) {
d_members = other.d_members;
d_special_members = new_special(other);
}
private:
vector<int*> new_special(const Widget& other) {
std::vector<int*> v;
v.reserve(other.d_special_members.size());
std::size_t special_index = 0;
for (std::size_t i = 0; i != d_members.size(); ++i) {
if (&other.d_members[i] == other.d_special_members[special_index]) {
v.push_back(&d_members[i});
++special_index;
}
}
return v;
}
};
My implementation runs in linear time and uses no extra space, but exploits the fact (based on your sample code) that there are no repeats in the pointers, and that the pointers are ordered the same as the original data.
I avoid copy and swap because it's not necessary to avoid code duplication and there just isn't any reason for it. It's a possible performance hit to get strong exception safety, that's all. However, writing a generic CAS that gives you strong exception safety with any correctly implemented class is trivial. Class writers should usually not use copy and swap for the assignment operator (there are, no doubt, exceptions).
This work for me for vector of pairs, though it's terribly ugly and I would never use it in real code:
std::vector<std::pair<int, int>> d_members;
std::vector<int*> d_special_members;
Widget(const Widget& other) : d_members(other.d_members) {
d_special_members.reserve(other.d_special_members.size());
for (const auto p : other.d_special_members) {
ptrdiff_t diff = (char*)p - (char*)(&other.d_members[0]);
d_special_members.push_back((int*)((char*)(&d_members[0]) + diff));
}
}
For sake of brevity I used only C-like type cast, reinterpret_cast would be better. I am not sure whether this solution does not result in undefined behavior, in fact I guess it does, but I dare to say that most compilers will generate a working program.
I think using indexes instead of pointers is just perfect. You don't need any custom copy code then.
For convenience you may want to define a member function converting the index to actual pointer you want. Then your members can be of arbitrary complexity.
private:
int* getSpecialMemberPointerFromIndex(int specialIndex)
{
return &d_member[specialIndex];
}

How to optimize std::map insert() function?

The best way to explain what I'm trying is accomplish is with this example (compiled with Visual Studio 2008 SP1):
struct ELEMENT1{
//Its members
ELEMENT1()
{
//Constructor code
}
~ELEMENT1()
{
//Destructor code
}
};
std::map<std::wstring, ELEMENT1> map;
std::pair<std::map<std::wstring, ELEMENT1>::iterator, bool> resIns;
ELEMENT1 element;
std::wstring strKey;
for(size_t i = 0; i < numberRepetitions; i++)
{
//Do processing
//...
//set 'strKey'
//Insert new element into the map first
resIns = map.insert(std::pair<std::wstring, ELEMENT1>(strKey, element)); //This line calls ELEMENT1 constructor & destructor twice
//Then fill out the data
fill_in_data(resIns.first->second);
}
BOOL fill_in_data(ELEMENT1& outInfo)
{
//Fill in 'outInfo' -- MUST be in its own function
//...
}
My goal is to optimize this code, and thus I did the following:
Moved ELEMENT1 element construction/destruction outside of the loop.
I'm inserting the element into the map and then attempt to fill it out using the pointer to the inserted element instead of constructing new element, then filling it out, then copying it into the map, and then destroying it. (At least that was the plan.)
But when I compile this for a Release build and check the assembler code, I can see that the C++ line with map.insert() function calls ELEMENT1 constructor twice! and then twice its destructor. So the following machine code is just for that map.insert() line:
So I'm obviously not seeing something here.
Can someone suggest what's going on in that compiled code & if it's possible to optimize it?
The reason you have 2 constructor calls is because what you are passing to insert does not match what it need. std::map::insert takes a const value_type& and value_type for a map is
std::pair<const key_type, element_type>
^^^^^ this is important
So, since they do not match you construct one element when you use
std::pair<std::wstring, ELEMENT1>(strKey, element)
and then the compiler calls the copy constructor to convert that into a
std::pair<const std::wstring, ELEMENT1>
A quick fix is to change the code to
std::pair<const std::wstring, ELEMENT1>(strKey, element)
Which leaves you with one temporary that is constructed and destructed. You can also do as zett42 suggests in their answer to avoid the creation of the temporary entirely.
resIns = map.insert(std::pair<std::wstring, ELEMENT1>(strKey, element));
You are constructing a temporary std::pair whose member second is a ELEMENT1. This causes the copy constructor of ELEMENT1 to be called.
The 2nd call to the copy constructor of ELEMENT1 is when std::map::insert() creates a new element in the map that will be initialized by the temporary std::pair.
You can avoid the duplicate constructor call caused by the temporary by using std::map::operator[] instead:
ELEMENT1& resIns = map[ strKey ];
fill_in_data( resIns );
If strKey doesn't already exist in the map, an ELEMENT1 will be default-constructed directly within the map and a reference to the new object will be returned. The constructor will be called exactly one time.
If strKey already exists in the map, a reference to the existing object will be returned.
You should use emplace to avoid creation on temp objects:
resIns = map.emplace
(
::std::piecewise_construct
, ::std::forward_as_tuple(strKey)
, ::std::forward_as_tuple()
);
A good reason to switch to newer VS version.

Emplacing a struct in unordered_map, reference issue

I have the following definition for boost unordered_map
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE> CLIENT_MAP;
Where CLIENT_STATE is an struct defined as follow:
typedef struct{
unsigned char state;
/* socket fd of the client */
int fd;
/* File path requested by the client */
char file_path [255];
/* Current file offset */
unsigned long int offset;
} CLIENT_STATE;
When I try to add an element to CLIENT_MAP using emplace, the CLIENT_MAP creates a separate copy of the element, not related to the original definition. i.e. any modifications to the original element definition, won't do any changes to the element in the unordered_map.
I was told before, that using emplace won't clone the my original element, it will place it directly in the container check the link
So what's the best way to let the changes to the added element in the container affects the original definition and vice versa.
This is what I mean:
CLIENT_STATE new_client;
new_client.offset = 5;
client_map.emplace("Test", new_client);
new_client.offset = 10;
cout << client_map["Test"].offest;
The cout won't print 10, it will print 5.
Currently to solve this issue, after an element to the unordered_map I work on the returned std::pair and do the modification, but I think it is not efficient way to do that.
emplace, allows an object to be constructed from the arguments passed into it without needing to create the object to be passed in first, saving an overhead by removing a copy construction which normally happens as the result of creating objects to be inserted.
You can achieve what you want by use of pointers
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE* > CLIENT_MAP;
But using pointers might prove problematic for memory handling, like object deletion, etc.
You can consider using boost::shared_ptr, something like following :
(I'm no shared_ptr/boost expert)
include <boost/shared_ptr.hpp>
boost::unordered::unordered_map<std::String,
boost::shared_ptr<CLIENT_STATE> > client_map ;
std::string s ="client1" ;
CLIENT_STATE *c1 = new CLIENT_STATE;
//c1->state, c1->id, etc
my_map[t] = c1 ;
If you needn't make copies of the objects stored in the map, you can use C++11's std::unique_ptr
You don't want to use emplace. What you want is called shared pointer semantics. However, for future visitors to this question, it may be useful to explain how to correctly use emplace with an associative container.
As #gha.st correctly commented, emplace will call the constructor of std::pair<std::string, CLIENT_STATE>, which will make copies of the string and CLIENT_STATE objects.
Since C++11, std::pair has an extra constructor overload taking a first argument of tag type std::piecewise_construct_t which allows the members of the std::pair themselves to be emplace-constructed. Observe:
client_map.emplace(std::piecewise_construct,
std::forward_as_tuple("Test"),
std::forward_as_tuple(5));
Now emplace will call the tag-overloaded constructor of pair, which in turn will emplace-construct its two data members from the arguments in the forwarded tuples.
In this case, CLIENT_STATE is an aggregate type, so (before C++20) it doesn't have a constructor which we can call with an int like this. But the above is the general technique to use with typical C++ class types. The best we can do for an aggregate before C++20 is to move-construct it from a temporary:
client_map.emplace("Test", CLIENT_STATE{ 0, 0, "", 5 });
In this case, this is of no help because the members of CLIENT_STATE are not move-constructible, so a move is the same as a copy.

Trying to wrap std containers to store rvalue references (like unique_ptr, but on the stack)

I'm trying to do strange things again.
Okay, here's the general idea. I want a std::list (and vector and so on) that actually own the objects they contain. I want to move the values into it, and access them by reference.
Example using a list of unique_ptr:
using namespace std;
list<unique_ptr<T>> items; // T is whatever type
items.push_back(make_unique(...));
items.push_back(make_unique(...));
for ( unique_ptr<T> item : items )
item.dosomething();
With me so far? Good. Now, let's do it with stack semantics and rvalue references. We can't just use a list<T&&> for obvious reasons, so we'd have to make a new class:
using namespace std;
owninglist<T> items;
items.push_back(T());
items.push_back(T());
for ( T& item : items )
item.dosomething();
Of course, I might want an owningstack or owningvector as well, so ideally we want it to be templated:
owning<std::list<T>> items;
The owning<U<T>> class should inherit whatever push_back() and pop_front() etc functions the underlying collection has. Presumably to achieve that, I'd need to code a generic base class, and derive explicit specialisations for the collections that have unusual functions:
template<typename T> owning<std::queue<T>> : owningbase<T> {
void push_front() { ... }
}
I'm getting stuck on the iterators. The begin() and end() functions should return an iterator that works the same as the underlying collection's iterator would, except with an operator*() that returns the item by lvalue reference instead of by value.
We'd need some way to transfer ownership of an item out of the list again. Perhaps the iterator could have an operator~ that returns the item as an rvalue, deletes the item from the list, and invalidates the iterator?
Of course, all this is assuming the underlying std::list (or whatever) can be convinced to take an rvalue. If push_back() copies the value in as an lvalue, then none of this is going to work. Would I be better off coding a container from scratch? If I did, is there some way to put the majority of the code for list, queue, stack and vector into a single base class, to save rewriting pretty much the same class four times over?
Perhaps I could introduce an intermediate class, some kind of wrapper? So owned<list<T>> could inherit from list<refwrapper<T>> or something? I know boost has a reference_wrapper, but I'm not sure it fits this scenario.
If you want to avoid copy elements around you can use std::move.
So if you have a std::list you can populate it with values by moving them in:
SomeBigObject sbo;
std::list<SomeBigObject> list;
list.push_back(SomeBigObject()); // SomeBigObject() is a rvalue and so it is moved
list.push_back(std::move(sbo)); // sbo may not be a rvalue so you have to move it
// For construction you can also use std::list::emplace
list.emplace(list.end()); // construct the value directly at the end of the list
For accessing them you can simply use the ranged based loop:
for(auto& i :list)
...
If you want to move them out of the container you can also use std::move.
The object is moved out of the container but the remains will still be in the container,
so you have to erase them:
for(auto it = list.begin; it != lsit.end();)
{
// the value of *it is moved into obj;
// an empty value of "SomeBigObject" will remain so erase it from the list
SomeBigObject obj = std::move(*it);
it = list.erase(it);
// do something with "obj"
...
}

Returning an STL vector from a function - copy cost

When you return an stl vector from a function:
vector<int> getLargeArray() { ... }
Is the return going to be an expensive copy operation? I remember reading somewhere that vector assignment being fast -- should I require the caller to pass a reference instead?
void getLargeArray( vector<int>& vec ) { ... }
Assuming your function constructs and returns new data, you should return by value, and try to make sure that the function itself has one return point that returns a variable of type vector<int>, or at worst several return points that all return the same variable.
That ensures that you'll get the named return value optimization on any credible compiler, which eliminates one of the potential copies (the one from the value in the function, to the return value). There are other ways to get a return value optimization, but it's not wholly predictable so the simple rule plays safe.
Next, you want to eliminate the potential copy from the return value to whatever the caller does with it. It's the caller's problem to solve, not the callee's, and there are basically three ways to do this:
Use the call to the function as the initializer for a vector<int>, in which case again any credible C++ compiler will elide the copy.
Use C++11, where vector has move semantics.
In C++03, use "swaptimization".
That is, in C++03 don't write
vector<int> v;
// use v for some stuff
// ...
// now I want fresh data in v:
v = getLargeArray();
Instead:
getLargeArray().swap(v);
This avoids the copy assignment that's required (must not be elided[*]) for v = getLargeArray(). It's not needed in C++11, where there's a cheap move assignment instead of the expensive copy assignment, but of course it still works.
Another thing to consider is whether you actually want vector as part of your interface. You could instead perhaps write a function template that takes an output iterator, and writes the data to that output iterator. Callers who want the data in a vector can then pass in the result of std::back_inserter, and so can callers who want the data in a deque or list. Callers who know the size of the data in advance could even pass just a vector iterator (suitably resize()d first) or a raw pointer to a large enough array, to avoid the overhead of back_insert_iterator. There are non-template ways of doing the same thing, but they'll most likely incur a call overhead one way or another. If you're worried about the cost of copying an int per element, then you're worried about the cost of a function call per element.
If your function doesn't construct and return new data, but rather it returns the current contents of some existing vector<int> and isn't allowed to change the original, then you can't avoid at least one copy when you return by value. So if the performance of that is a proven problem, then you need to look at some API other than return-by-value. For example you might supply a pair of iterators that can be used to traverse the internal data, a function to look up a value in the vector by index, or even (if the performance problem is so serious as to warrant exposing your internals), a reference to the vector. Obviously in all those cases you change the meaning of the function -- now instead of giving the caller "their own data" it provides a view of someone else's data, which might change.
[*] of course the "as if" rule still applies, and one can imagine a C++ implementation that's smart enough to realise that since this is a vector of a trivially copyable type (int), and since you haven't taken any pointers to any elements (I assume), then it can swap instead and the result is "as if" it copied. But I wouldn't count on it.
You are very likely to get return value optimization, depending on the structure of the function body. In C++11 you could also benefit from move semantics.
Returning by value certainly has cleaner semantics, and I would see it as the preferred option, unless profiling proves it to be costly. There is a good related article here.
Here is a small example with a verbose dummy class, compiled with no optimization or C++11 support, using an old-ish version of GCC (4.3.4):
#include <vector>
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo()\n"; }
Foo(const Foo&) { std::cout << "Foo copy\n"; }
Foo& operator=(const Foo&) {
std::cout << "Foo assignment\n";
return *this;
}
};
std::vector<Foo> makeFoos()
{
std::vector<Foo> tmp;
tmp.push_back(Foo());
std::cout << "returning\n";
return tmp;
}
int main()
{
std::vector<Foo> foos = makeFoos();
}
The result on my platform is that all copying happens before the function return. If I compile with C++11 support, then the push_back results in a move copy rather than a C++03 copy construction.