Inherit copy constructor - c++11

Say I have a class A, which provide a copy constructor (accepting another A).
I then have a derived class B of A, which does not provide a copy constructor.
Can I inherit the copy constructor of A into B, alike what's possible for non-copy constructors?
Note: B does not have any state, except the state contained in A.

If you don't need any special behaviour in addition to what the base class's copy constructor provides, you should be fine with simply telling the compiler to use the default copy constructor, which will invoke the base classes copy constructor
#include <iostream>
class A {
public:
int a;
A()=default;
A(const A& other) {
std::cout << "Class A copy constructor called" << std::endl;
a = other.a;
}
};
class B: public A {
public :
int b;
B() = default;
B(const B& other) = default;
};
int main() {
B b1;
b1.a = 1;
b1.b = 2;
B b2(b1);
std::cout << b2.a << " - " << b2.b << std::endl;
}
Output:
Class A copy constructor called
1 - 2
EDIT:
In order to answer your exact question: I believe that the using directive makes all base class constructors visible in the derived class. I'm personally not too fond of this behavior, so I prefer using the default constructors instead of the using directive, but that's just me.

Related

Does emplace_back construct an object in its new location instead of using a move?

From this link it states
For example, in the code that we began with, my_vec.push_back("foo")
constructs a temporary string from the string literal, and then moves
that string into the container, whereas my_vec.emplace_back("foo")
just constructs the string directly in the container, avoiding the
extra move. For more expensive types, this may be a reason to use
emplace_back() instead of push_back(), despite the readability and
safety costs, but then again it may not. Very often the performance
difference just won’t matter
So I decided to try that and this is what i did
class foo
{
public:
int counter;
foo()
{
std::cout << "Regular constructor\n";
}
foo(const foo& f)
{
std::cout << "Copy constructor\n";
}
foo(foo&& f)
{
std::cout << "Move constructor\n";
}
};
int main()
{
std::vector<foo> f;
f.push_back(foo()); //Regular constructor and Move Constructor
f.emplace_back(foo()); //Regular constructor and Move Constructor
}
I noticed that both push_back and emplace_back behave similarly. I was thinking that emplace_back will only be calling the regular constructor based on what I read since it will be constructed in the vector stack.
vector::emplace_back(Args&&...) takes the arguments of the constructor you want to construct your new object with. In your quoted example this is const char* for the constructor string::string(const char*). In your own code you're forcing the move constructor by passing a temporary object. To default-construct your object in-place use f.emplace_back() without any arguments as the default constructor takes none.
Also to avoid reallocation (potentially more moves that would spoil your test) ensure the vector has space for your two test objects first using f.reserve(2).
Full code:
class foo
{
public:
foo()
{
std::cout << "Default constructor\n";
}
foo(const foo& f)
{
std::cout << "Copy constructor\n";
}
foo(foo&& f)
{
std::cout << "Move constructor\n";
}
};
int main()
{
std::vector<foo> f;
f.reserve(2);
f.push_back(foo());
f.emplace_back();
}
Output is
Default constructor
Move constructor
Default constructor

Are all the data members initialized to 0 or are they assigned random values by the constructor which is called automatically?

I tried to check what values are assigned to the data members when we do not call a constructor manually. I got 0 for both a and b, but I got 1 for c, so how are the data members initialized? Randomly or to 0? And if they are initialized to 0, why am I seeing 1 as the value for c?
#include<iostream>
using namespace std;
class Class
{
public:
int a,b,c;
};
int main()
{
Class obj;
cout<<obj.a;
cout<<"\n";
cout<<obj.b;
cout<<"\n";
cout<<obj.c;
return 0;
}
The output is
0
0
1
But I expected
0
0
0
As stated here the default initialization in your case will led to "undetermined" i.e. undefined values.
The compiler will provide you with a default constructor because you haven't defined it yourself and did not defined any other constructors (it will delete it in that case), but the default constructor will still make the member values undefined. You were getting 0s and a 1 - I was getting numbers more like 1515788312.
With C++11 standard you can prevent this by providing the default values directly in the class,
#include<iostream>
using namespace std;
class Class
{
public:
int a = 0, b = 0, c = 0;
};
int main()
{
Class obj;
cout<< obj.a << " "
<< obj.b << " " << obj.c << endl;
return 0;
}
In this case, the values will be initialized to whatever you set them to be. To achieve the same thing you can also simply provide your own default constructor,
#include<iostream>
using namespace std;
class Class
{
public:
Class() : a(1), b(2), c(3) { }
int a, b, c;
};
int main()
{
Class obj;
cout<< obj.a << " "
<< obj.b << " " << obj.c << endl;
return 0;
}
As a side note, avoid using namespace std due to possible name collisions. Use individual using statements instead - for things you commonly use like cout. I changed your program a little bit for clarity. Also, the answers to your question can be found well explained in various C++ books, like Lippman's Primer which I used.

What does unique_ptr<T>::operator= do in terms of deallocation

I'm having troubles understanding fully the assignment operator for unique_ptr. I understand that we can only move them, due to the fact that copy constructor and assignment operators are deleted, but what if
a unique_ptr which contains already an allocation is overwritten by a move operation? Is the content previously stored in the smart pointer free'd?
#include <iostream>
#include <memory>
class A{
public:
A() = default;
virtual void act() const {
std::cout << "act from A" << std::endl;
}
virtual ~A() {
std::cout << "destroyed A" << std::endl;
}
};
class B : public A {
public:
B() : A{} {}
void act() const override {
std::cout << "act from B" << std::endl;
}
~B() override {
std::cout << "destroyed from B " << std::endl;
}
};
int main() {
auto pP{std::make_unique<A>()};
pP->act();
==================== ! =======================
pP = std::make_unique<B>(); // || std::move(std::make_unique<B>())
==================== ! =======================
pP->act();
return 0;
}
When I do
pP = std::make_unique<B>();
does it mean that what was allocated in the first lines for pP (new A()) is destructed automatically?
Or should I opt for:
pP.reset();
pP = std::make_unique<B>();
Yes, see section 20.9.1, paragraph 4 of the C++11 draft standard
Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of
such a transfer, the following postconditions hold:
u2.p is equal to the pre-transfer u.p,
u.p is equal to nullptr, and
if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
As in the case of a reset, u2 must properly dispose of its pre-transfer owned object via the pre-transfer
associated deleter before the ownership transfer is considered complete
In other words, it's cleaning up after itself upon assignment like you'd expect.
Yes, replacing the content of a smart pointer will release the previously-held resource. You do not need to call reset() explicitly (nor would anyone expect you to).
Just for the sake of this particular example. It seems polymorphism in your example didn't allow you to draw clear conclusions from output:
act from A
destroyed A
act from B
destroyed from B
destroyed A
So let's simplify your example and make it straight to the point:
#include <iostream>
#include <memory>
struct A {
explicit A(int id): id_(id)
{}
~A()
{
std::cout << "destroyed " << id_ << std::endl;
}
int id_;
};
int main() {
std::unique_ptr<A> pP{std::make_unique<A>(1)};
pP = std::make_unique<A>(2);
}
which outputs:
destroyed 1
destroyed 2
Online
I hope this leaves no room for misinterpretation.

behavior of synthesised move constructor

I am reading C++ Primer 5th edition and get the following problems. The book lists several cases that a synthesized move operation is defined as deleted. One of which is "Unlike the copy constructor, the move constructor is defined as deleted if the class has a member that defines its own copy constructor but does not also define a move constructor, or if the class has a member that doesn't define its own copy operations and for which the compiler is unable to synthesize a move constructor. Similarly for move-assignment."
and also provide an demo code as following:
// assume Y is a class that defines its own copy constructor but not a move constructor
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem; // hasY will have a deleted move constructor
};
hasY hy, hy2 = std::move(hy); // error: move constructor is deleted
However, for both gcc 7.2.1 and clang-900.0.37, the code is runnable, is the book wrong?
Here is the complete test code:
#include <iostream>
struct Y {
Y() { std::cout << "Y()" << std::endl; }
Y(const Y&) { std::cout << "Y(const Y&)" << std::endl; }
//Y(Y&&) { cout << "Y(Y&&)" << endl; }
};
// assume Y is a class that defines its own copy constructor but not a move constructor
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem; // hasY will have a deleted move constructor
};
int main() {
hasY hy, hy2 = std::move(hy); // error: move constructor is deleted
return 0;
}
The book correctly describes the behavior prescribed by the C++11 standard. The prescribed behavior, however, has changed as of C++14, which adopted the resolution of Defect Report #1402 "Move functions too often deleted"

Is this an example of reference reassignment? C++11

As I understand it, one cannot change the reference variable once it has been initialized. See, for instance, this question. However, here is a minmal working example which sort of does reassign it. What am I misunderstanding? Why does the example print both 42 and 43?
#include <iostream>
class T {
int x;
public:
T(int xx) : x(xx) {}
friend std::ostream &operator<<(std::ostream &dst, T &t) {
dst << t.x;
return dst;
}
};
int main() {
auto t = T(42);
auto q = T(43);
auto &ref = t;
std::cerr << ref << std::endl;
ref = q;
std::cerr << ref << std::endl;
return 0;
}
You're not changing the reference here.
You are replacing the object the reference is referring to.
In other words: after the assignment, your t is replaced by q.
ref is still a reference to t.
That does not perform a reference reassignment. Instead, it copy assigns the object in variable q into the object referenced by ref (which is t in your example).
This also justifies why you got 42 as output: the default copy assignment operator modified the first object.

Resources