According to C++11 [12.8.9], this (nontrivial) class X does not have an implicitly declared move constructor, because X has a user-declared copy ctor, a user-declared copy assignment operator, a user-declared dtor:
// This counter for objects of class X is only there to make X 'nontrivial':
static int xc = 0;
class X {
public:
X() : p(42) { ++xc; /* ...more nontrivial stuff... */; }
explicit X(const int &t) noexcept : p(t) { ++xc; /* ... */ }
X(const X & other) noexcept : p(other.p) { ++xc; /* ... */ }
//X(X &&) = delete; /* **this is the line in question** */
X& operator=(const X & other) { p = other.p; /* ... */ return *this; }
X& operator=(X && other) { p = other.p; /* ... */ return *this; }
~X() { --xc; /* ... */ }
private:
int p;
};
However, if I uncomment the deleted move ctor (i.e. if I delete the move ctor), my compiler (GCC 5.2) suddenly complains about the move ctor being deleted when compiling this:
X f(int x)
{
return X(x);
}
I would have supposed that with out deleted move ctor the compiler uses the copy ctor when returning an X from function f since an implicit move ctor is not allowed here. But then: why does it make a difference to explicitly delete the move ctor?
The terms "not defined" and "deleted" move constructor are different. Explicitly defined move constructor is chosen by overload resolution even if it is deleted.
If you want to forbid object moving and prevent overload resolution from selecting deleted move constructor, the move constructor should be implicitly deleted:
(since C++14)The deleted implicitly-declared move constructor is
ignored by overload resolution (otherwise it would prevent
copy-initialization from rvalue)
For example, you can inherit the class from base class with deleted move constructor.
Related
In summary, I have a class inherited from std::enabled_shared_from_this, and there is a factory method return an std::unique_ptr of it. In another class, I convert the std::unique_ptr of the previous class object to std::shared_ptr, and then I call shared_from_this(), which then throws std::bad_weak_ptr. The code is shown below:
#include <memory>
#include <iostream>
struct Executor;
struct Executor1 {
Executor1(const std::shared_ptr<Executor>& executor,
int x): parent(executor) {
std::cout << x << std::endl;
}
std::shared_ptr<Executor> parent;
};
struct Backend {
virtual ~Backend() {}
virtual void run() = 0;
};
struct Executor: public Backend, public std::enable_shared_from_this<Executor> {
const int data = 10;
virtual void run() override {
Executor1 x(shared_from_this(), data);
}
};
// std::shared_ptr<Backend> createBackend() {
std::unique_ptr<Backend> createBackend() {
return std::make_unique<Executor>();
}
class MainInstance {
private:
std::shared_ptr<Backend> backend;
public:
MainInstance(): backend(createBackend()) {
backend->run();
}
};
int main() {
MainInstance m;
return 0;
}
Indeed changing std::unique_ptr<Backend> createBackend() to std::shared_ptr<Backend> createBackend() can solve the problem, but as I understand, in general, the factory pattern should prefer return a unique_ptr. Considering a good pratice of software engineering, is there a better solution?
[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (23.11.2.5), then [magic happens that makes shared_from_this() work for *p - IT]
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
[util.smartptr.shared.const]/29 Effects: ... equivalent to shared_ptr(r.release(), r.get_deleter())...
template<class Y, class D> shared_ptr(Y* p, D d);
[util.smartptr.shared.const]/10 Effects: ... enable shared_from_this with p
Your example executes std::shared_ptr<Backend>(uptr) where uptr is std::unique_ptr<Backend>, which is equivalent to std::shared_ptr<Backend>(p, d) where p is of type Backend*. This constructor enables shared_from_this with p - but that's a no-op, as Backend doesn't have an unambiguous and accessible base class that is a specialization of enable_shared_from_this
In order for Executor::enable_from_this to work, you need to pass to a shared_ptr constructor a pointer whose static type is Executor* (or some type derived therefrom).
Ok, I find a simple solution, that is, using auto as the return type of the factory function, instead of std::unique_ptr or std::shared_ptr, and keeping std::make_unique inside the factory function. The factory function createBackend should be:
auto createBackend() {
return std::make_unique<Executor>();
}
In this case, the return type can be automatically determined, although I don't know how it works exactly. This code can return either unique_ptr or shared_ptr, which should be better than just using shared_ptr. I tested clang and gcc, and both of them worked, but I am still not sure if this is gauranteed by the type deduction and the implicit conversion.
Update:
Actually, I have found that auto deduces the return type above as std::unique_ptr<Executor> instead of std::unique_ptr<Backend>, which might be the reason why the code works. But using auto has an issue: if you return the smart pointer in an if-else block, where the return type varies depending on some parameters, then auto cannot determine the type. For example:
std::unique_ptr<Backend> createBackend(int k = 0) {
if (k == 0) {
return std::make_unique<Executor>();
}
else {
return std::make_unique<Intepreter>();
}
}
Here, both Executor and Intepreter derive from Backend. I think a correct solution includes:
Inherit Backend instead of its derived classes from std::enable_shared_from_this;
Use dynamic_pointer_cast<Derived class> to cast the shared_ptr to derived class after shared_from_this.
The full code is listed in:
https://gist.github.com/HanatoK/8d91a8ed71271e526d9becac0b20f758
I'm working with an expression template class which should not be instantiated to avoid dangling references. But I'm temped to declare a variable with auto and 'auto' create a named instance of a temporary class.
How can I disable auto declaration of temporary class in the following code?
class Base
{
};
class Temp : public Base
{
public:
Temp() {}
Temp(int, int) {}
Temp(const Temp&) = default;
Temp(Temp&&) = default;
};
Temp testFunc(int a, int b) {
return Temp{a,b};
}
int main() {
Base a = testFunc(1,2); // this should work
auto b = testFunc(1,2); // this should fail to compile
return 0;
}
You seem to want to prevent users from using auto on a particular type. That's not possible in any version of C++. If it is legal C++ for a user to write T t = <expr>;, where T is the type of <expr>, then it will be legal for a user to write auto t = <expr>; (ignoring class data members). Just as you cannot forbid someone from passing <expr> to a template function using template argument deduction.
Anything you do to prevent auto usage will also inhibit some other usage of the type.
One option would be to make Temp's constructors private, move testFunc inside the Temp class and make it static. This way you can still instantiate Base, but auto would fail because you would be calling a private constructor:
class Base
{
};
class Temp : public Base
{
Temp() {}
Temp(int, int) {}
Temp(const Temp&) = default;
Temp(Temp&&) = default;
public:
static Temp testFunc(int a, int b)
{
return Temp{a,b};
}
};
int main() {
Base a = Temp::testFunc(1,2); // this should work
auto b = Temp::testFunc(1,2); // this should fail to compile
return 0;
}
Demo
I have a small program like below:
class boovector{
private: int size;
char *arr;
public:
boovector(){size=1;arr=new char[size];cout<<" boovector default constructor called"<<endl;}
boovector(boovector &b)
{
cout<<"boovector copyconstructor called"<<endl;
size = b.size;
arr = new char[size];
strncpy(arr,b.arr,size);
}
boovector(boovector &&b)
{
cout<<"boovector move assignment operator called"<<endl;
size =b.size;
arr = b.arr;
b.arr = nullptr;
}
~boovector()
{
delete []arr;
}
};
boovector createboovector()
{
boovector v;
return v;
}
void foo(boovector v)
{
}
int main(int argc, char *argv[])
{
boovector vet = createboovector();
foo(vet);
foo(createboovector());
return 0;
}
Output
boovector default constructor called
boovector copyconstructor called
boovector default constructor called
I was hoping to see "boovector move assignment operator called" in the output.
If I comment move constructor "boovector(boovector &&b)", i get compiler error
invalid initialization of non-const reference of type 'boovector&' from an
rvalue of type 'boovector'
I want to understand the logic behind the move constructor not being called.
In my case on MSVC 2017 Community Edition the produced output is:
boovector default constructor called
boovector move assignment operator called
boovector copyconstructor called
boovector default constructor called
boovector move assignment operator called
So it works as expected.
I don't understand why a class that has a deleted copy constructor (or contains a member, like ifstream, that has a deleted copy constructor and there it, too, has a deleted copy constructor) can't be used with make_shared()? This code shows what I'm talking about
class X {
private:
X(const X&) = delete;
int x;
public:
X(int an_int) : x{an_int} {};
X() : x{10} {}
};
int main(int argc, char** argv)
{
// fails because X has no copy constructor
shared_ptr<X> ptr { make_shared<X>( X{8} ) };
shared_ptr<X> ptr2 { new X{10} };// works fine
return 0;
}
You may be missing the fact that make_shared will forward its arguments to the constructor of X. In this case you are passing X{8} as the constructor argument, so make_shared is forced to attempt copy or move construction.
In this particular example, deleting the copy constructor has implicitly deleted the move constructor, preventing construction from the temporary X{8}.
What you probably want to write is this:
shared_ptr<X> ptr { make_shared<X>(8) };
I have a beginner question on the move assigment in c++11. Let say that I have a class A provided with a move assigment operator:
class A
{
public:
A();
~A();
A& operator=(A&&);
...
}
I also have a class B containing a class A object and provided with a move assignment operator
class B
{
public:
B();
~B();
B& operator=(B&&);
...
private:
A Test;
}
What I was thinking is that the B move assignment operator will call the move assignment operator of its member so I tried this method:
B& B::operator=(B&& Other)
{
...
Test = Other.Test;
...
return *this;
}
But this is not working since the move assignment of class A is not called.
Instead I was able to make the program work by using this method:
B& B::operator=(B&& Other)
{
...
Test = std::move(Other.Test);
...
return *this;
}
I do not understand why the first method is not working. I was thinking that since a constructor will call its members constructors the move assignment operator should do the same. Am I wrong or I made a mistake in my code? Can someone explain, thanks!
Other.Test is not an rvalue expression since it has a name. OTOH std::move(Other.Test) has the type A and the value category xvalue (i.e., an rvalue). Thus, it can bind to the move constructor.
(EDIT : Shamelessly copied #dyp's comment. Thanks, #dyp and #KerrekSB.)
#Pradhan is correct - you need to use std::move to move the members in the implementation of the move assignment operator. However, if that is all that is needed to implement your move constructor, then you can declare the operator to use the default implementation:
#include <memory>
class A {
public:
A() : p{} { }
~A() { }
A &operator=(A &&) = default;
// Instead of:
// A &operator=(A &&other) {
// p = std::move(other.p);
// return *this;
// }
private:
std::unique_ptr<int> p;
};
int main() {
A a;
A b;
b = std::move(a);
return 0;
}