C++ In-place Construction And Piecewise-Construction

Rico Ruotong Jia
2 min readFeb 12, 2024

--

Save whenever you can not whenever you have to — John D. Rockefeller

Imagine we have a LIDAR/Radar map of an unknown territory in a game, or real world robot navigation. On this map, we estimate a map based on how many times each scanned pixel point has been been detected. So, we have a class Pixel2DWithCount to keep track of the detection count along with the pixel itself.

struct Pixel2DWithCount {
int x, y;
unsigned int total_count_ = 1;
unsigned int hit_count_ = 0;
}

If the the territory is large, we have a huge number of pixels that need to be tracked. Therefore, when storing into a container, we want to construct the new objects in-place. Since C++11, in C++ STL containers, emplace() or emplace_back() are functions for this purpose.

emplace(iterator, args&&) are seen in many STL containers, such as std::unordered_map, std::set, std::vector . We can pass in position (iterator) in the container for the insertion, and args&& are used to construct the new object, possibly through move semantics. emplace_back() are seen in std::vector, std::list, std::deque .

How To Set Up For Emplace()

In this section, we are trying to add the new object into an std::unordered_map called count_map .

First, we need a custom constructor (ctor), because the default aggregation initialization does not work with in-place construction std::unordered_map::emplace(args) without creating an extra copy

  Pixel2DWithCount(int x_, int y_, unsigned int hit_count_)
: x(x_), y(y_), hit_count_(hit_count_) {}

Second, count_map.emplace(j, Rigid2D::Pixel2DWithCount(j, j, 1)); works, because C++ still synthesizes a copy ctor despite a custom one is defined. C++ won’t synthesize the copy ctor / copy assignment operator unless you declare it deleted, or a custom move ctor/move assignment operator is defined.

Then, one could do in-place construction using std::piecewise_construct (defined in <utility>).

int main()
{
// int is index
std::unordered_map<int, Pixel2DWithCount> m;
m.emplace(std::piecewise_construct, std::make_tuple(1), std::make_tuple(1,2));

return 0;
}

However, this method requires us to create a tuple for std::make_tuple(1) , which is unnecessary.

Well, thanks for reading this far. As you might have guessed, alternatively, one can do m.emplace(1, Foo(1,2)); . This makes use of the default move ctor and a new object should be built in place

--

--

Rico Ruotong Jia
Rico Ruotong Jia

Written by Rico Ruotong Jia

A singer, a gym goer, a robot enthusiast, a human being. Northwestern University MSc. Robotics

No responses yet