construct std::pair in-place in vector::emplace_back - c++11

I have a class A defined like bellow:
class A
{
public:
A() = default;
explicit A(uint32_t a, uint32_t b)
{
std::cout << "construct" << std::endl;
}
A(const A& obj)
{
std::cout << "copy" << std::endl;
*this = obj;
}
A(const A&& obj)
{
std::cout << "move" << std::endl;
*this = obj;
}
A& operator=(const A& obj)
{
std::cout << "copy operator" << std::endl;
return *this;
}
A& operator=(const A&& obj)
{
std::cout << "move operator" << std::endl;
}
};
I use the class like this:
std::vector<std::pair<A, bool>> v;
v.emplace_back(A(0, 1), true);
The emplace_back has the following output:
construct
move
copy operator
My question is, is there any way to construct A of the pair in-place without calling the move and copy operator?

Yes, std::pair has this constructor:
cppreference/utility/pair/pair
template< class... Args1, class... Args2 >
pair( std::piecewise_construct_t,
std::tuple<Args1...> first_args,
std::tuple<Args2...> second_args );
Forwards the elements of first_args to the constructor of first and forwards the elements of second_args to the constructor of second. This is the only non-default constructor that can be used to create a pair of non-copyable non-movable types.
You can therefore invoke:
std::vector<std::pair<A, bool>> v;
v.emplace_back(std::piecewise_construct,
std::make_tuple(0, 1),
std::make_tuple(true));

Related

Return “this” as rvalue

The following code does, as expected, not compile
#include <iostream>
class A
{
public:
A() = default;
~A() = default;
A(const A&) = delete;
A(A&&) = delete;
A& operator=(const A&) = delete;
A& operator=(A&&) = delete;
A& operator<<(const int i)
{
std::cout << "operator<< called" << std::endl;
return *this;
}
};
void foo(A&& a)
{
std::cout << "foo called" << std::endl;
}
int main()
{
A a; a << 14;
foo(std::move(a)); // works fine
foo(A() << 14); // does not compile
return 0;
}
Changing the class A to
class A
{
public:
A() = default;
~A() = default;
A(const A&) = delete;
A(A&&) = delete;
A& operator=(const A&) = delete;
A& operator=(A&&) = delete;
A& operator<<(const int i) &
{
std::cout << "operator<< called on lvalue" << std::endl;
return *this;
}
A&& operator<<(const int i) &&
{
std::cout << "operator<< called on rvalue" << std::endl;
return std::move(*this);
}
};
makes the program compile. However, return rvalues with std::move is usually not a good idea, since it will return dangling references or prevents the compiler to do certain optimizations.
Is the described case one of the few exception from the rule of thumb "do not return by rvalue" or should the issue be resolved differently?
Great thanks!
This code is perfectly valid and safe. As your object is already an rvalue in
A&& operator<<(const int i) &&
casting it to rvalue again (with move) will not change security of the code. NRVO optimization will not take place in this case so speed of the code is unlikely to be affected.
So as you formulate it I'd say "yes, this is an exception to the rule"
Also this rule is not universal: if you understand what's going on (which is why you asked this question) you can rely on your good sense instead of it.

why map emplace calling rvalue constructor twice

class twoMem {
int _a;
int _b;
public:
twoMem() {
std::cout << "default constructor" << std::endl;
}
twoMem(int a, int b) :_a(a), _b(b) {
std::cout << "constructor called" << std::endl;
}
twoMem(const twoMem& other) {
std::cout << "copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
twoMem(const twoMem&& other) {
std::cout << "rvalue copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
~twoMem() {
std::cout << "destructor called" << std::endl;
}
};
int main()
{
std::map<std::string, twoMem> myMap{};
myMap.emplace(std::make_pair("foo", twoMem{ 1, 2 }));
return 0;
}
output:
constructor called
rvalue copy constructor called
rvalue copy constructor called
destructor called
destructor called
destructor called
First, make_pair moves from twoMem argument into pair<const char*, twoMem> it returns. Second, emplace() moves from that into actual node.
Make it
myMap.emplace("foo", twoMem{ 1, 2 });
then the move constructor is only called once. That's kind of the point of map::emplace.
You can get to zero copy or move constructors this way:
myMap.emplace(std::piecewise_construct, std::make_tuple("foo"), std::make_tuple(1, 2));
Though arguably this cure may be worse than the disease, as now you are constructing and copying tuples around, which is likely at least as expensive as copying twoMem.

Using move semantics to avoid copying when pushing_back to a custom container does not avoid copying

I have implemented a custom container (same vein as std::vector) and I am trying to make it so that its 'push_back' function would use leverage on move semantics to avoid creating a copy of whatever is being pushed back - specially when the object to be pushed into the container is returned by an external function.
After reading quite a bit about move semantics and custom containers, I still can't find why my approach is still generating a copy instead of just moving the passed object into the container's inner dynamic array.
Here is a simplified version of my container looks like:
template<class T>
class Constructor
{
private:
size_t size = 0;
size_t cap = 0;
T *data = nullptr;
public:
Constructor()
{
cap = 1;
size = 0;
data = static_cast<T*>(malloc(cap * sizeof(T)));
}
~Constructor()
{ delete[] data; }
template<typename U>
void push_back(U &&value)
{
if (size + 1 >= cap)
{
size_t new_cap = (cap * 2);
T* new_data = static_cast<T*>(malloc(new_cap * sizeof(T)));
memmove(new_data, data, (size) * sizeof(T));
for (size_t i = 0; i<cap; i++)
{
data[i].~T();
}
delete[] data;
cap = new_cap;
data = new_data;
new(data + size) T(std::forward<U>(value));
}
else
{
new(data + size) T(std::forward<U>(value));
}
++size;
}
const T& operator[](const size_t index) const //access [] overloading
{
return data[index];
}
};
Here is a custom class that will print messages when its instances are created, copied or moved, in order to help debugging:
class MyClass
{
size_t id;
public:
MyClass(const size_t new_id)
{
id = new_id;
std::cout << "new instance with id " << id << std::endl;
}
MyClass(const MyClass &passedEntity)
{
id = passedEntity.id;
std::cout << "copied instance" << std::endl;
}
MyClass(MyClass &&passedEntity)
{
id = passedEntity.id;
std::cout << "moved instance" << std::endl;
}
void printID() const
{
std::cout << "this instance's id is " << id << std::endl;
}
};
And here is the external function:
MyClass &foo(MyClass &passed)
{
return passed;
}
Lastly, here is the main function that runs a test case using the above function and classes to show the problem:
int main()
{
MyClass a(33);
std::cout << std::endl;
std::cout << "Using my custom container: " << std::endl;
Constructor<MyClass> myContainer;
myContainer.push_back(foo(a));
myContainer[0].printID();
std::cout << std::endl;
std::cout << "Using dinamic array: " << std::endl;
MyClass *dinArray = static_cast<MyClass*>(malloc(1 * sizeof(MyClass)));
dinArray = new(dinArray + 1) MyClass(std::forward<MyClass>(foo(a)));
dinArray[0].printID();
std::cout << std::endl;
system("Pause");
return 0;
}
The output is:
new instance with id 33
Using my custom container:
copied instance
this instance's id is 33
Using dinamic array:
moved instance
this instance's id is 33
As it can be seen, if the instance of MyClass is put directly into a dynamic array, then just the move conmstructor is called and not the copy constructor. However, if I push_back the yClass instance into an instance of Container, a copy constructor is still being called.
Could someone help me understand what exactly am I doing wrong here? How could I make it so that elements are pushed into the container without generating a copy?
When you call this line
myContainer.push_back(foo(a));
L-value is passed into push_back method, and now read about using std::forward - http://www.cplusplus.com/reference/utility/forward/,
Returns an rvalue reference to arg if arg is not an lvalue reference.
If arg is an lvalue reference, the function returns arg without modifying its type.
and in your push_back you call
new(data + size) T(std::forward<U>(value));
but value was passed as L-value, and only constructor MyClass(const MyClass &passedEntity) can be invoked.
If you want a object to be moved, you can write
myContainer.push_back(std::move(a)); // cast to R-reference
EDIT
You should not use move in your push_back function, below is simple example.
Suppose you have class like this:
struct Foo {
int i;
Foo (int i = 0) : i(i) {
}
~Foo () {
}
Foo (const Foo& ) {
}
Foo& operator=(const Foo&) {
return *this;
}
Foo (Foo&& f)
{
i = f.i;
f.i = 0; // this is important
}
Foo& operator=(Foo&& f)
{
i = f.i;
f.i = 0; // this is important
return *this;
}
};
we have also 2 functions
template<class T>
void process1 (const T& ) {
cout << "process1" << endl;
}
template<class T>
void process (T&& obj) {
cout << "process2" << endl;
T newObj = forward<T>(obj);
}
and bars functions are counterparts of your push_back method.
template <typename T>
void bar1 (T&& value) {
process (move(value)); // you use move in your push_back method
}
template <typename T>
void bar2 (T&& value) {
process (forward<T>(value));
}
now we must consider 4 cases:
[1] pass L-value, version with forward
Foo f(20);
bar2 (f);
cout << (f.i) << endl; // 20
[2] pass R-value, version with forward
Foo f(20);
bar2 (move(f));
cout << (f.i) << endl; // 0, it is OK bacuse we wanted to move 'f' object
[3] pass R-value, version with move
Foo f(20);
bar1 (move(f));
cout << (f.i) << endl; // 0, ok, we wanted to move 'f' object
[4] pass L-value, version with move in your push_back method
Foo f(20);
bar1 (f);
cout << (f.i) << endl; // 0 !!! is it OK ? WRONG
in last case, we passed f as L-value, but this object was moved in bar1 function, for me this is strange behavior and is incorrect.
It is not safe to perform a memmove with objects in C++.
You can find more information here Will memcpy or memmove cause problems copying classes?
If this is C++11 onwards, then what you want to use is placement new and the move constructor. (you could probably just bin the placement new though unless you really want to keep allocating memory yourself)
If this is any other version of C++ then you'll have to just accept that that either you're going to have to copy the object (like the rest of the stl) or that your object will have to implement a function like void moveTo(T& other)

What does String do that I'm not doing? c++11

I am still new to c++, so bear with me.
I was trying to learn more about how std::move works and I saw an example where they used std::move to move the string to a different function and then showed using std::cout that no string remained. I thought cool, let's see if I can make my own class and do the same:
#include <iostream>
#include <string>
class integer
{
private:
int *m_i;
public:
integer(int i=0) : m_i(new int{i})
{
std::cout << "Calling Constructor\n";
}
~integer()
{
if(m_i != nullptr) {
std::cout << "Deleting integer\n";
delete m_i;
m_i = nullptr;
}
}
integer(integer&& i) : m_i(nullptr) // move constructor
{
std::cout << "Move Constructor\n";
m_i = i.m_i;
i.m_i = nullptr;
}
integer(const integer& i) : m_i(new int) { // copy constructor
std::cout << "Copy Constructor\n";
*m_i = *(i.m_i);
}
//*
integer& operator=(integer&& i) { // move assignment
std::cout << "Move Assignment\n";
if(&i != this) {
delete m_i;
m_i = i.m_i;
i.m_i = nullptr;
}
return *this;
}
integer& operator=(const integer &i) { // copy assignment
std::cout << "Copy Assignment\n";
if(&i != this) {
m_i = new int;
*m_i = *(i.m_i);
}
return *this;
}
int& operator*() const { return *m_i; }
int* operator->() const { return m_i; }
bool empty() const noexcept {
if(m_i == nullptr) return true;
return false;
}
friend std::ostream& operator<<(std::ostream &out, const integer i) {
if(i.empty()) {
std::cout << "During overload, i is empty\n";
return out;
}
out << *(i.m_i);
return out;
}
};
void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; }
void g(std::string s) { std::cout << "The g value is " << s << '\n'; }
int main()
{
std::string s("Hello");
std::cout << "Now for string\n";
g(std::move(s));
if(s.empty()) std::cout << "s is empty\n";
g(s);
std::cout << "\nNow for integer\n";
integer i = 77;
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
std::cout << "Move it\n";
g(std::move(i)); // rvalue ref called
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
return 0;
}
And this is my output:
Now for string
The g value is Hello
s is empty
The g value is
Now for integer
Calling Constructor
Copy Constructor
i is 77
Deleting integer
Copy Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
Move it
Move Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
i is empty
Copy Constructor
Process returned 255 (0xFF) execution time : 7.633 s
Press any key to continue.
As you can see, it crashes when it enters g the second time, never even getting to the operator<<() function. How is it that the empty std::string s can be passed to g where my empty integer i crashes the program?
Edit: Fixed new int vs. new int[] error. Thanks n.m.
Your "empty integer" crashes the program because it contains a null pointer. You are trying to dereference it when you use it at the right hand side of the assignment.
An empty string is a normal usable string. There are no unchecked null pointer dereferences in the std::string code.
You have to ensure that the empty state of your object is a usable one. Start with defining a default constructor. Does it make sense for your class? If not, then move semantic probably doesn't either. If yes, a moved-from object in the move constructor should probably end up in the same state as a default-constructed object. A move assignment can act as a swap operation, so there the right-hand-side may end up either empty or not.
If you don't want to define a usable empty state for your class, and still want move semantics, you simply cannot use an object after it has been moved from. You still need to make sure that an empty object is destructible.

smart pointers with POD Structures and inheritance

I am developing an application that uses POD C++ structures. This was working fine until I needed to have 2 variants of a one of my POD structs. Introducing virtual inheritance (due to the presence of the virtual destructor in the base class) in order to manage these similar POD structures in a polymorphic manner (as they share common base fields) changes the overall size of the derived data structures – as it needs to accommodate the vtable. Not having a virtual base class on the other hand introduces data slicing during smart pointer destructors.
Is there some way around this such that I can maintain the ease of managing these PODS through their base class while not introducing data slicing/memory leaks when the std::unique_ptr’s destructors get called.
I put together a simple live coliru demo showing the various aspects of the POD structs I encountered, unfortunately I do not know how to contain these in vector of virtual base unique pointers. Any help/design pointers would be greatly appreciated.
struct VBase {
uint32_t mBaseInt;
// allow default construction using placement operator
VBase() = default;
// copy constructor
VBase(const VBase&) = default;
// move constructor
VBase(VBase&&) = default;
// explicit constructor
explicit VBase(const uint32_t val)
: mBaseInt(val)
{
std::cout << "VBase(val)" << std::endl;
}
virtual ~VBase() = default;
} __attribute__((packed));
struct Derived1 : VBase {
uint32_t mDerivedInt;
// allow default construction using placement operator
Derived1() = default;
// copy constructor
Derived1(const Derived1&) = default;
// move constructor
Derived1(Derived1&&) = default;
// explicit constructor
explicit Derived1(const uint32_t val, const uint32_t val1)
: VBase(val)
, mDerivedInt(val1)
{
std::cout << "Derived1(val, val1)" << std::endl;
}
~Derived1() {
std::cout << "~Derived1()" << std::endl;
};
} __attribute__((packed));
struct Derived2 : VBase {
uint32_t mDerivedInt1;
uint32_t mDerivedInt2;
// allow default construction using placement operator
Derived2() = default;
// copy constructor
Derived2(const Derived2&) = default;
// move constructor
Derived2(Derived2&&) = default;
// explicit constructor
explicit Derived2(
const uint32_t val,
const uint32_t val1,
const uint32_t val2)
: VBase(val)
, mDerivedInt1(val1)
, mDerivedInt2(val2)
{
std::cout << "Derived2(val, val1, val2)" << std::endl;
}
virtual ~Derived2() {
std::cout << "~Derived2()" << std::endl;
};
} __attribute__((packed));
struct NVBase {
explicit NVBase() {
std::cout << " NVBase()" << std::endl;
}
~NVBase() {
std::cout << "~NVBase()" << std::endl;
};
} __attribute__((packed));
struct D : NVBase {
uint16_t f;
explicit D()
: NVBase()
{}
~D() {
std::cout << "~D()" << std::endl;
};
} __attribute__((packed));
int main()
{
std::vector<std::string> words = {
"Hello", "from", "GCC", __VERSION__, "!"
};
std::cout << words << std::endl;
std::cout << "sizeof(VBase)=" << sizeof(VBase) << std::endl;
std::cout << "sizeof(Derived1)=" << sizeof(Derived1) <<std::endl;
std::cout << "sizeof(Derived2)=" << sizeof(Derived2)<< std::endl;
std::cout << "sizeof(NVBase)=" << sizeof(NVBase) << std::endl;
std::cout << "sizeof(D)=" << sizeof(D) << std::endl;
std::unique_ptr<VBase> pVBase = std::make_unique<Derived1>(1,2);
std::unique_ptr<NVBase> pNVDerived = std::make_unique<D>();
std::cout << sizeof(*pVBase) << std::endl;
std::cout << sizeof(*pNVDerived) << std::endl;
std::vector<std::unique_ptr<VBase>> vec = {
//std::make_unique<Derived1>(1,2)
};
// vec.emplace_back(std::move(*pVBase));
}

Resources