Constructor - Copying Const Reference VS Moving Copied Value - c++

I couldn't find the answer so I'm asking it here. What's the difference between THIS:
class Foo
{
public:
Foo(std::string string)
: m_String(std::move(string)) {}
private:
std::string m_String;
}
And THAT:
class Bar
{
public:
Bar(const std::string& string)
: m_String(string) {}
private:
std::string m_String;
}
I know that using a constructor from Bar copies data exactly from the value, but I don't really know what exactly happens when calling the Foo constructor.
Is there a difference in using constructor from Foo or Bar?

Don't use strings but a type where you can observe copying and moving:
#include <iostream>
struct test {
test() { std::cout << "constructor\n"; }
test(const test&) { std::cout << "copy\n";}
test(test&&) { std::cout << "move\n"; }
};
class Foo {
public:
Foo(test t) : t(std::move(t)) {}
private:
test t;
};
class Bar {
public:
Bar(const test& t) : t(t) {}
private:
test t;
};
int main() {
test t1;
Foo f{t1};
std::cout << "...........\n";
test t2;
Bar b{t2};
}
Output:
constructor
copy
move
...........
constructor
copy
Calling Foos constructor copies t1 to the constructors parameter, because it is taken by value and then the member is move constructed from the parameter.
Calling Bars constructor takes a reference (no copy, no move) and uses that to copy construct the member.
If the intention was to avoid the copying, you would provide a constructor that takes a test&&:
struct Baz {
Baz(test&& t) : t(std::move(t)) {}
test t;
};
Then Baz z(test{}); will construct a test and the member will be move constructed from that temporary. No copies involved.

Related

Copy Constructors of classes instantiating derived classes

I have unsuccessfully been trying to create a copy constructor of a class that instantiates a derived class.
Let's say I have the following pure virtual class:
class AbstractBar{
public:
virtual void printMe() = 0;
};
Class Bar inherits from AbstractBar as follows:
class Bar: public AbstractBar {
std::string name_;
public:
explicit Bar(std::string name) : name_ {std::move(name)}{};
void printMe() override { std::cout << name_ << std::endl; }
};
My class Foo now attempts to make use of polymorphism by declaring a pointer to type AbstractClass as follows:
class Foo{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar){
theBar_ = std::move(bar);
};
void printBar(){
theBar_->printMe();
}
};
I do however want Foo to be copied so I add the following copy constructor:
Foo(const Foo &other) {
theBar_ = std::unique_ptr<AbstractBar>();
*theBar_ = *(other.theBar_);
}
And this is where it breaks.
What I gather is that this may be a problem since theBar in the copy constructor thinks it is pointing to an AbstractBar but when I try to copy the object it points to, in the next line, I actually give it a derived Bar class.
Is there a proper way to implement this copy constructor?
First off, std::unique_ptr<T> is indeed unique. Therefore you cannot expect two things to point to the same instance-of-whatever by copying them. That said, I think what you're trying to do is clone whatever the "thing" is that is held by that member unique_ptr to allow a deep copy of a Foo.
If that is the case, you need a covariant clone. See below:
#include <iostream>
#include <string>
#include <memory>
struct AbstractBar
{
virtual ~AbstractBar() = default;
virtual std::unique_ptr<AbstractBar> clone() = 0;
virtual void printMe() = 0;
};
class Bar : public AbstractBar
{
std::string name_;
public:
explicit Bar(std::string name) : name_{std::move(name)} {};
std::unique_ptr<AbstractBar> clone() override
{
return std::make_unique<Bar>(name_);
}
void printMe() override
{
std::cout << name_ << std::endl;
}
};
class Foo
{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar)
: theBar_(std::move(bar))
{
}
Foo(const Foo &other)
: theBar_(other.theBar_->clone())
{
}
void printBar()
{
theBar_->printMe();
}
};
int main()
{
Foo foo(std::make_unique<Bar>("Some String"));
Foo bar(foo);
foo.printBar();
bar.printBar();
}
Important: foo and bar will each have their own Bar instance via a unique pointer to the abstract base of Bar, namely AbstractBar. Hopefully that was the intent. This isn't the only way to do this, but it is probably the easiest to understand.

How do I set a default value for a class member with something other than its initializer list constructor

Let's say I have something like this:
class A
{
public:
A(int x, int y)
{
std::cout << "Constructed from parameters" << std::endl;
}
// Non-copyable, non-movable
A(A const&) = delete;
A(A&&) = delete;
A& operator=(A const&) = delete;
A& operator=(A&&) = delete;
};
class B
{
public:
B() = default;
private:
A a{1,2};
};
int main()
{
B b;
return 0;
}
This works fine, initializes a with a default value by calling A's constructor, and prints Constructed from parameters.
Then, let's say I want to initialize a differently, so I add a constructor that takes an initializer list and change my code:
class A
{
public:
A(int x, int y)
{
std::cout << "Constructed from parameters" << std::endl;
}
A(std::initializer_list<int> someList)
{
std::cout << "Constructed from an initializer list" << std::endl;
}
// Non-copyable, non-movable
A(A const&) = delete;
A(A&&) = delete;
A& operator=(A const&) = delete;
A& operator=(A&&) = delete;
};
class B
{
public:
B() = default;
private:
A a{1,2,3};
};
int main()
{
B b;
return 0;
}
Everything still works as I want, the code initializes a with a default value by calling A's second constructor and prints Constructed from an initializer list.
Now, let's say I want to keep A as is but go back to setting a's default value through the first constructor. If A was movable, I could use A a = A(1,2);, but that isn't the case here, so how do I go about this? Is it plain impossible to set a default value with that constructor?
Edit: I'm looking for a solution that would work with C++14, but if there is a better solution in C++17 or C++20 that's also something I want to know.
If A was movable, I could use A a = A(1,2);, but that isn't the case
here
Well, for C++17 and later, you can use A a = A(1,2); here, so long as you have that as the declaration/initialisation! The following works (in your second code snippet):
class B {
public:
B() = default;
private:
A a = A( 1, 2 ); // No assignment here - just an initialization.
};
and "Constructed from parameters" is called. This is because there is no actual assignment operation here, just an initialization. However, the following would fail, for the reason you have stated:
class B {
public:
B() { a = A( 1, 2 ); } // error C2280: 'A &A::operator =(A &&)': attempting to reference a deleted function
private:
A a{ 1,2,3 };
};
EDIT: Pre-C++17, the following is a workaround, using the 'old-fashioned' round parentheses, rather than curly braces, in an initializer list in the default constructor for B (tested with C++14 in clang-cl and MSVC):
class B {
public:
B() : a(1,2) {} // Using a{1,2} calls the "initializer list" constructor, however!
private:
A a;
};
I think this is not possible in C++14 without some kind of a "hack". One such hack is to employ an additional disambiguating parameter. For example:
class From_params {};
class A {
public:
A(int, int, From_params = {}) // (1)
{}
A(std::initializer_list<int>) // (2)
{}
...
};
class B {
public:
B() = default;
private:
A a{1, 2, From_params{}}; // calls (1)
};

How to properly initialize copy constructor (of constructor with class as reference)

How do you initialize a copy constructor of constructor that has as reference a class. I simply do not know what to put after the colon in order to initialize it.
class Me{
public:
Me (const otherMe& t)
:other_me(t)
{}
//copy constructor
Me(const Me& me)
: /*what do you put here in order to write
the line of code bellow. I tried t(t), and gives me the
warning 'Me::t is initialized with itself [-Winit-self]' */
{cout << t.getSomthing() << endl;}
private:
const otherMe& other_me;
};
Let's say you have two classes, Value, and Wrapper:
class Value { // stuff... };
class Wrapper; // This one contains the reference
We can write the constructor and copy-constructor like so:
class Wrapper {
Value& val;
public:
Wrapper(Value& v) : val(v) {}
Wrapper(Wrapper const& w) : val(w.val) {}
};
This wold also work if Value& were a const reference! In addition, if you can write Wrapper as an aggregate, it'll automatically get a copy constructor:
class Wrapper {
public:
Value& val;
// copy constructor automatically generated
};

copy constructor of a vector-derived class

I have the following classes.
class CA {
...
};
class CB: public vector<CA> {
...
};
How shall I implement the copy constructor of CB? i.e.,
CB(CB& cb).
How do I copy the content of the vector of cb in?
Ignoring the issue with publicly inheriting from an std::vector, if you really need a copy constructor for your derived type (for instance, if you are managing dynamically allocated resources), then you can use the constructor initialization list, as in this example, where Foo takes the place of your std::vector in the inheritance hierarchy:
#include <iostream>
struct Foo
{
Foo() {}
Foo(const Foo&) { std::cout << "Copy Foo\n";}
};
struct Bar : public Foo
{
Bar() {}
Bar(const Bar& b) : Foo(b) {}
};
int main()
{
Bar b1;
Bar b2(b1);
}

passing 'const Class2' as 'this' argument of 'int Class1::get_data()' discards qualifiers

I'm trying to set up a copy constructor and i'm getting this error
class Class1{
public:
int get_data();
void set_data(int);
private:
int d;
};
int Class1::get_data(){
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
Class2(const Class2&);
};
Class2::Class2(const Class2 &c2) : Class1(){
set_data(c2.set_data());
}
whats a solution to this problem. i read some of the previous questions and i understand why this is happening. but making set_data() const is not an option.
whats the accepted approach for copy constructors?
thanks,
You could just write a constructor for Class1 taking an int parameter:
class Class1 {
explicit Class1 (int i) : d (i) {}
// as before
};
class Class2 : public Class1 {
Class2 (Class2 const & c2) : Class1 (c2.get_data ()) {}
};
However, the default copy constructor should be enought here (i.e. you don't need to write your own, the compiler will do it for you).
Generally speaking, you should use initialisation lists:
http://www.parashift.com/c++-faq-lite/ctors.html
in the constructors (read the whole entry in the faq)
Edit: You forgot the 'const' qualifier for your get_data function.
Don't you want:
set_data(c2.get_data());
(and make the Class1::get_data() member function const)?
But you really should be using constructor initialization lists:
Class2::Class2(const Class2 &c2)
: Class1(c2)
{
}
This code uses the compiler-generated default copy constructor for Class1. In many cases you shouldn't use the default copy constructor or copy-assign operator overload, but here it's fine because the sole data member of Class1 is an int object.
In fact, you could even rely on the compiler-generated default copy constructor for Class2.
EDIT: Here is some example code:
#include <iostream>
class Class1{
public:
Class1() : d(0) { } // Provide a no-arg constructor to initialize `d`
int get_data() const; // Class1::get_data() is `const` because it does not change the `Class1` object.
void set_data(int);
private:
int d;
};
int Class1::get_data() const{
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
public:
Class2();
};
Class2::Class2()
: Class1()
{
}
int main() {
Class2 other_c2;
other_c2.set_data(14);
Class2 c2(other_c2);
std::cout << c2.get_data() << '\n';
}
http://codepad.org/jlplTYrH