I can't figure out how push_back(const value_type& val) exactly works, in docs it says about val that
val is Value to be copied (or moved) to the new element ...
How it can be copied when it takes val by reference ?
Will that copying ever call the copy constructor of val ?
and what's exactly happening here ?
#include <iostream>
#include <vector>
using namespace std;
struct x
{
x(int v = 0) : v(v) {}
int v;
};
vector<vector<x>> parts;
void fillParts()
{
vector<x> values = { x(1), x(2), x(3) };
parts.push_back(values);
}
int main()
{
fillParts();
parts[0][0].v = -123;
cout << parts[0][0].v; // -123
return 0;
}
this runs with no erros,
is parts[0] is a reference to local vector values or a copy ?
if it is a reference shouldn't it at least give some warnings saying that your accessing and modifying local objects of freed stack ?
How it can be copied when it takes val by reference?
Think of a copy constructor.
It takes parameter by reference, and it performs copying perfectly.
class Bar
{
public:
Bar(const Bar & rhs); // by reference, to copy.
};
Will that copying ever call the copy constructor of val ?
Copy operation uses copy constructor.
You can actually see if it's copied, or moved by providing user-defined constructors.
struct x
{
public:
x(const x & rhs)
{
// Some copy operation.
std::cout << "Copied" << std::endl;
}
x(x && rhs)
{
// Some move operation.
std::cout << "Moved" << std::endl;
}
};
You can try this
class A
{
public:
A() {}
A(const A&) { cout << "copy cons" << endl; }
A& operator= (A &&) { cout << "move" << endl; };
A& operator= (const A &) { cout << "copy" << endl; };
};
vector<A> parts;
void fillParts()
{
A a;
parts.push_back(a);
}
int main()
{
fillParts();
return 0;
}
I got copy cons called in both debug and release builds.
Related
I have two similar pieces of code. The first version unexpectedly calls the default constructor while the second doesn't. They both call the move operator / move constructor, respectively, as expected.
class MyResource
{
public:
MyResource() : m_data(0) { std::cout << "Default Ctor" << std::endl; }
MyResource(int data) : m_data(data) { std::cout << "Int Ctor" << std::endl; }
MyResource(MyResource const& other) = delete;
MyResource& operator=(MyResource const& other) = delete;
MyResource(MyResource&& other) noexcept : m_data(other.m_data) { std::cout << "Move Ctor" << std::endl; }
MyResource& operator=(MyResource&& other) noexcept { std::cout << "Move Op" << std::endl; m_data = other.m_data; return *this; }
~MyResource() { std::cout << "Dtor" << std::endl; }
private:
int m_data = 0;
};
class MyWrapper
{
public:
MyWrapper(MyResource&& resource)
// : m_resource(std::move(resource)) // Version 2
{
// m_resource = std::move(resource); // Version 1
}
private:
MyResource m_resource;
};
My test usage is:
MyWrapper* wrapper = new MyWrapper(MyResource(1));
delete wrapper;
With Version 1, I get:
Int Ctor
Default Ctor
Move Op
Dtor
Dtor
While Version 2 outputs:
Int Ctor
Move Ctor
Dtor
Dtor
What's the reason behind this difference?
Why does version 1 call the default constructor?
Members are initialized before the construct body runs. A much simpler example to see the same:
#include <iostream>
struct foo {
foo(int) { std::cout << "ctr\n";}
foo() { std::cout << "default ctr\n";}
void operator=(const foo&) { std::cout << "assignment\n"; }
};
struct bar {
foo f;
bar(int) : f(1) {}
bar() {
f = foo();
}
};
int main() {
bar b;
std::cout << "---------\n";
bar c(1);
}
Output:
default ctr
default ctr
assignment
---------
ctr
You cannot initialize a member in the body of the constructor! If you do not provide an initializer, either in the member initializer list or as an in class initializer, then f is default constructed. In the constructor body you can only assign to an already initialized member.
I have a generic code at which point I leave a possibility to modify data.
if (impl_.mode() == implementation_type::manual)
{
const auto steering = custom::customize_steering(impl_, input.steering());
impl_.output_interface()(steering);
return impl_.do_continue(impl_.params().period());
}
By default I want customize_steering to be optimized out.
Now I have it this way:
template<typename ImplT, typename SteeringT>
constexpr std::decay_t<SteeringT> customize_steering(ImplT &, SteeringT &&steering)
{
return std::forward<SteeringT>(steering);
}
Is it the right way to do or is it too convoluted and passing by const reference will do fine?
I decided to check, and I don't get the results I expect.
#include <iostream>
class foo
{
public:
foo() { std::cout << "Constructed" << std::endl; }
foo(const foo &) { std::cout << "Copy constructed" << std::endl; }
foo(foo &&) { std::cout << "Move constructed" << std::endl; }
~foo() { std::cout << "Destroyed" << std::endl; }
};
template<typename T>
std::decay_t<T> do_nothing(T &&t)
{
return std::forward<T>(t);
// return t;
}
int main(int, char **)
{
const auto &fcr = do_nothing(do_nothing(do_nothing(foo())));
const auto fc = do_nothing(fcr);
return 0;
}
The output is (MinGW64):
Constructed
Move constructed
Move constructed
Move constructed
Destroyed
Destroyed
Destroyed
Copy constructed
Destroyed
Destroyed
What I expected:
Without mandatory copy elision: Constructor -> Move constructor.
With mandatory copy elision (C++17): Constructor (for const auto fc).
How can I make it work?
I am starting with C++ environment, I hope I didn't mess up a lot with the concepts here.
I have one task where I need to create an object that has to be able to be copied in two ways, with a shallow copy and a deep copy.
The object has to allow two types of copies. Either the object is shallow copied or deep copy depending on the demands.
In the code below I create a simple example to explain the use case. There, I implement the object Object with a one-argument constructor and a deep copy constructor. Then at some point we use the functions get_shallow and get_deep.
Is there a way to tell the compiler which constructor to use when it copies Object in the scope of the functions? Sometimes I will need a function to return the shallow copy and other times a deep copy.
using namespace std;
class Object;
typedef std::shared_ptr<Object> objectPtr;
class Object{
private:
int *data;
public:
Object(int d);
Object(const Object &source);
~Object();
};
// One argument constructor
Object::Object(int d) {
data = new int;
*data = d;
}
//deep copy constructor
Object::Object(const Object &source) :Object(*source.data) {}
Object::~Object() {delete data;}
Object get_shallow(Object object) {
return object;
}
Object get_deep(Object object) {
return object;
}
int main(){
Object object1 {100};
get_deep(object1); //returns a deep copy of the object
get_shallow(object1); //returns a shallow copy of the object
return 0;
}
You can use a tag on the copy constructor to indicate it is making a shallow copy.
Note carefully that a shallow copy does not own the resources. So when the owner gets destructed, any shallow copy will have dangling pointers. That's a very fragile situation, and easily the source of bugs.
An alternative solution is to have a std::shared_ptr for the shared resources, and then those resources exist until all owners relinquish ownership (typically relinquishing ownership upon destruction, but could be that they change ownership over the lifecycle of the entity object).
Regardless, here's an example of shallow copy constructor.
#include <iostream>
using std::cout;
using std::ostream;
class Object {
int* data;
bool delete_data = true;
public:
enum Shallow_tag { shallow };
~Object();
Object(int d);
Object(Object const&); // DEEP copy.
Object(Object const&, Shallow_tag); // SHALLOW copy.
bool is_shallow() const { return !delete_data; }
auto get_data() const -> int* { return data; }
};
Object::~Object() { if (delete_data) delete data; }
// One argument constructor
Object::Object(int d) : data{new int(d)} { }
//deep copy constructor
Object::Object(Object const& other) : Object(*other.data) {}
// shallow copy
Object::Object(Object const& other, Shallow_tag) : data{other.data}, delete_data{false} {}
Object get_shallow(Object const& object) {
return Object(object, Object::shallow);
}
Object get_deep(Object object) {
return object;
}
ostream& operator<<(ostream& out, Object const& obj) {
out << (obj.is_shallow() ? "shallow" : "deep") << " ";
auto d = obj.get_data();
if (d) out << "data:" << *d;
else out << "data:(null)";
return out;
}
int main() {
auto object1 = Object{100};
auto obj2 = get_deep(object1); //returns a deep copy of the object
auto obj3 = get_shallow(object1); //returns a shallow copy of the object
cout << "obj2 is " << obj2 << "\n";
cout << "obj3 is " << obj3 << "\n";
}
UPDATE: using shared_ptr for the data.
Of course, an int as shared data is probably a bit silly. But for the purposes of an example it is illustrative of whatever the data payload type.
#include <iostream>
#include <memory>
using std::cout;
using std::make_shared;
using std::ostream;
using std::shared_ptr;
class Object {
shared_ptr<int> data;
public:
Object(int d);
auto get_data() const -> int* { return data.get(); }
};
Object::Object(int d) : data{make_shared<int>(d)} { }
auto operator<<(ostream& out, Object const& obj) -> ostream& {
auto d = obj.get_data();
if (d) out << "data:" << *d;
else out << "data:(null)";
return out;
}
Object get_copy(Object o) {
return o;
}
int main() {
auto object1 = Object{100};
auto obj2 = get_copy(object1);
auto obj3 = get_copy(object1);
cout << "obj2 is " << obj2 << "\n"; // 100
cout << "obj3 is " << obj3 << "\n"; // 100
*object1.get_data() = 5;
cout << "obj2 is " << obj2 << "\n"; // 5
cout << "obj3 is " << obj3 << "\n"; // 5
obj2 = Object{75};
cout << "obj2 is " << obj2 << "\n"; // 75
cout << "obj3 is " << obj3 << "\n"; // 5
}
Playing around with the source code from Dangerous implicit conversion in emplace I detected the following behavior:
struct Foo
{
public:
explicit Foo(const int& i) : i(i) {
cout << "explicit int ctor called" << endl; }
explicit Foo(const double& x) : i(i) {
cout << " explicit double ctor called // i : " << i << endl; }
Foo(int&&) = delete;
Foo(double&&) = delete;
void foo() const {
cout << i << endl; }
private:
const int& i;
};
void bar(const double& d) {
cout << "---------- create object vector ------------" << endl;
std::vector<Foo> fv;
fv.emplace_back(d);
fv[0].foo();
cout << "---------- create object default ------------" << endl;
Foo f(d);
f.foo();
}
int main(){
bar(5.0);
return 0;
}
Prints:
---------- create object vector ------------
explicit double ctor called // i : 5
0
---------- create object default ------------
explicit double ctor called // i : 5
5
Thus in both cases the reference member gets correctly initialized during object creation, indicated by the outputs i = 1. But after calling the foo() function on both objects they yield different results. Retrieving the recently emplaced Object from the vector prints 0 even thought it should print 1. The other object performs right.
Question Why is the value of the const reference member not persistent when emplaced in the STL container ? (I am not interested in advices like "simply do not use (const) references as class members.)
On this line:
explicit Foo(const double& x) : i(i) {
The member reference i is initialized with itself, which causes undefined behaviour.
I'm trying to create an immutable class in C++11, which (for convenience) provides methods that modify the current state. To satisfy the immutable contract, these methods must return a new instance with the updated contents.
In the following snippet, ImmutableObject::setA() and ImmutableObject::setB() update the a and b attributes in a new instance of ImmutableObject created via a copy constructor and return it. The method print() just displays the content.
int main(int argc, char **argv) {
ImmutableObject().setA(1).setB(2).print();
return 0;
}
(An implementation of ImmutableObject is provided below.)
Implementing this naively using C++03 causes an unnecessary copies to be created.
I am wondering if C++11 move semantics can be used to exploit the fact that ImmutableObject() and the return value of setA() are just temporary copies that could be directly updated.
I already added a rvalue copy and assignment constructor in the code below, but it does not look like it's working. When running the program, I get
In constructor
In copy constructor
In copy constructor
a=1, b=2
Any advice would be greatly appreciated!
#include <iostream>
using namespace std;
class ImmutableObject {
public:
ImmutableObject() {
std::cout << "In constructor" << std::endl;
}
ImmutableObject(const ImmutableObject &obj) : a(obj.a), b(obj.b) {
std::cout << "In copy constructor" << std::endl;
}
ImmutableObject(ImmutableObject&& other) {
std::cout << "In move constructor" << std::endl;
a = other.a;
b = other.b;
}
ImmutableObject &operator=(ImmutableObject&& other) {
if (this != &other) {
a = other.a;
b = other.b;
}
return *this;
}
ImmutableObject setA(int value) {
ImmutableObject result(*this);
result.a = value;
return result;
}
ImmutableObject setB(int value) {
ImmutableObject result(*this);
result.b = value;
return result;
}
void print() {
std::cout << "a=" << a << ", b=" << b << std::endl;
}
private:
int a;
int b;
};