我从gcc收到一个奇怪的错误,无法弄清楚原因.我制作了以下示例代码,以使问题更加清晰.基本上,有一个类定义,我为其复制构造函数和复制赋值运算符私有,以防止意外调用它们.
#include <vector>
#include <cstdio>
using std::vector;
class branch
{
public:
int th;
private:
branch( const branch& other );
const branch& operator=( const branch& other );
public:
branch() : th(0) {}
branch( branch&& other )
{
printf( "called! other.th=%d\n", other.th );
}
const branch& operator=( branch&& other )
{
printf( "called! other.th=%d\n", other.th );
return (*this);
}
};
int main()
{
vector<branch> v;
branch a;
v.push_back( std::move(a) );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望这段代码能够编译,但是gcc失败了.实际上gcc抱怨"branch :: branch(const branch&)是私有的",据我所知,不应该调用它.
赋值运算符可以工作,因为如果我用main替换main()的主体
branch a;
branch b; …Run Code Online (Sandbox Code Playgroud) MSDN文章如何:编写移动构造函数具有以下建议.
如果为类提供移动构造函数和移动赋值运算符,则可以通过编写移动构造函数来调用移动赋值运算符来消除冗余代码.以下示例显示了调用移动赋值运算符的移动构造函数的修订版本:
// Move constructor.
MemoryBlock(MemoryBlock&& other)
: _data(NULL)
, _length(0)
{
*this = std::move(other);
}
Run Code Online (Sandbox Code Playgroud)
这个代码是通过双重初始化MemoryBlock的值来实现低效的,还是编译器能够优化掉额外的初始化?我是否应该通过调用移动赋值运算符来编写移动构造函数?
我有几个类,我想检查是否正在生成默认的移动构造函数.有没有办法检查这个(无论是编译时断言,还是解析生成的目标文件,还是别的东西)?
励志示例:
class MyStruct : public ComplicatedBaseClass {
std::vector<std::string> foo; // possibly huge
ComplicatedSubObject bar;
};
Run Code Online (Sandbox Code Playgroud)
如果任何类的任何基Complicated...Object类或成员的任何成员都不能被移动,MyStruct则不会生成其隐式移动构造函数,并且因此可能无法优化复制foo工作,即使foo可移动也可以进行移动.
我希望避免:
我已经尝试过以下内容但它们不起作用:
std::move明确使用- 如果没有可用的移动ctor,这将调用复制ctor.std::is_move_constructible-this将在复制构造函数接受时成功const Type&,默认情况下生成(只要移动构造函数未被显式删除,至少).nm -C以检查移动构造函数的存在[见下文].但是,另一种方法是可行的[见答案].我试着看一下像这样的普通类的生成符号:
#include <utility>
struct MyStruct {
MyStruct(int x) : x(x) {}
//MyStruct(const MyStruct& rhs) : x(rhs.x) {}
//MyStruct(MyStruct&& rhs) : x(rhs.x) {}
int x;
};
int main() {
MyStruct s1(4); …Run Code Online (Sandbox Code Playgroud) 当类使用多重继承时,如何安全地设计移动构造函数?
请考虑以下情形:
struct T { };
struct U { };
struct X : public T, public U
{
X(X&& other)
: T(std::move(other))
, U(std::move(other)) // already moved?!
{
}
};
Run Code Online (Sandbox Code Playgroud)
有没有办法移动 - 构建T和U安全?
c++ multiple-inheritance move-constructor move-semantics c++11
我试图理解移动构造函数和赋值操作在C++ 11中的工作方式,但是我遇到了委托父类的问题.
代码:
class T0
{
public:
T0() { puts("ctor 0"); }
~T0() { puts("dtor 0"); }
T0(T0 const&) { puts("copy 0"); }
T0(T0&&) { puts("move 0"); }
T0& operator=(T0 const&) { puts("assign 0"); return *this; }
T0& operator=(T0&&) { puts("move assign 0"); return *this; }
};
class T : public T0
{
public:
T(): T0() { puts("ctor"); }
~T() { puts("dtor"); }
T(T const& o): T0(o) { puts("copy"); }
T(T&& o): T0(o) { puts("move"); }
T& operator=(T const& o) …Run Code Online (Sandbox Code Playgroud) 第一个例子:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const A&) = delete;
A(A&&) = default;
A(const int i) : ref(new int(i)) { }
~A() = default;
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它完美地运作.所以这里使用了MOVE构造函数.
让我们删除移动构造函数并添加一个副本:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const A&a)
: ref( a.ref.get() ? new int(*a.ref) : nullptr )
{ }
A(A&&) = delete;
A(const int i) : ref(new …Run Code Online (Sandbox Code Playgroud) 我有一个基类,它基本上将一个类附加到任意窗口句柄(例如,HWND,HFONT),并使用策略类来附加/分离和销毁:
// class SmartHandle
template<typename THANDLE, class TWRAPPER, class TPOLICY>
class SmartHandle : boost::noncopyable
{
private:
TPOLICY* m_pPolicy; // Policy
bool m_bIsTemporary; // Is this a temporary window?
SmartHandle(); // no default ctor
SmartHandle(const SmartHandle<THANDLE, TWRAPPER, TPOLICY>&); // no cctor
protected:
THANDLE m_hHandle; // Handle to the underlying window
TPOLICY& policy() {return(*m_pPolicy);};
// ctor that attaches but is temporary
SmartHandle(const THANDLE& _handle, bool _temporary) : m_hHandle(_handle)
, m_bIsTemporary(_temporary)
{
m_pPolicy = new TPOLICY(reinterpret_cast<TWRAPPER&>(*this));
if(_handle)
m_pPolicy->attach(_handle);
}; // eo ctor
// …Run Code Online (Sandbox Code Playgroud) 假设我有一个(普通的)类,它是可移动构造和可移动分配但不可复制构造或可复制分配:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
这很好用:
movable m1(movable(17));
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为m1它不是右值:
movable m2(m1);
Run Code Online (Sandbox Code Playgroud)
但是,我可以包m1中std::move,它投射到一个右值引用,以使其工作:
movable m2(std::move(m1));
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,假设我有一个(同样微不足道的)容器类,它包含一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用:
container<movable> c(movable(17));
Run Code Online (Sandbox Code Playgroud)
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨我正在尝试movable在container初始化列表中使用已删除的复制构造函数.同样,包裹value在std::move使得它的工作:
explicit container(T&& value) : value_(std::move(value)) {} …Run Code Online (Sandbox Code Playgroud) 没有移动构造函数但带有接受const T&参数的复制构造函数的类型满足std::is_move_constructible.例如,在以下代码中:
#include <type_traits>
struct T {
T(const T&) {}
//T(T&&) = delete;
};
int main() {
static_assert(std::is_move_constructible<T>::value, "not move constructible");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
T 将没有隐式移动构造函数,因为它具有用户定义的复制构造函数.
但是,如果我们取消注释移动构造函数的显式删除,则代码不再编译.为什么是这样?我原以为显式复制构造函数仍然会满足std::is_move_constructible.
重载是否起作用,选择声明的移动构造函数然后失败,因为它被删除了?
如果a no implicit move ctor和deleted move ctorclass 之间的移动构造性之间的差异是由标准规定的,请引用,并且如果可能的话,给出一个基本原理(例如"提供禁止移动构造的设施" - 首先想到的事情).
下面的代码可以使用Visual Studio 2015成功编译,但使用Visual Studio 2017失败.Visual Studio 2017报告:
错误C2280:"std :: pair :: pair(const std :: pair&)":尝试引用已删除的函数
#include <unordered_map>
#include <memory>
struct Node
{
std::unordered_map<int, std::unique_ptr<int>> map_;
// Uncommenting the following two lines will pass Visual Studio 2017 compilation
//Node(Node&& o) = default;
//Node() = default;
};
int main()
{
std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
看起来Visual Studio 2017显式需要移动构造函数声明.是什么原因?