Irf*_*rfy 17 c++ move-constructor c++11
我有几个类,我想检查是否正在生成默认的移动构造函数.有没有办法检查这个(无论是编译时断言,还是解析生成的目标文件,还是别的东西)?
励志示例:
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);
MyStruct s2(s1);
MyStruct s3(std::move(s1));
return s1.x + s2.x + s3.x; // Make sure nothing is optimized away
}
Run Code Online (Sandbox Code Playgroud)
生成的符号如下所示:
$ CXXFLAGS="-std=gnu++11 -O0" make -B x; ./x; echo $?; nm -C x | grep MyStruct | cut -d' ' -f3,4,5
g++ -std=gnu++11 -O0 x.cc -o x
12
.pdata$_ZN8MyStructC1Ei
.pdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.text$_ZN8MyStructC1Ei
.text$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.xdata$_ZN8MyStructC1Ei
.xdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
MyStruct::MyStruct(int)
std::remove_reference<MyStruct&>::type&&
Run Code Online (Sandbox Code Playgroud)
当我明确默认复制并移动ctors(无符号)时,输出相同.
使用我自己的副本和移动ctors,输出看起来像这样:
$ vim x.cc; CXXFLAGS="-std=gnu++11 -O0" make -B x; ./x; echo $?; nm -C x | grep MyStruct | cut -d' ' -f3,4,5
g++ -std=gnu++11 -O0 x.cc -o x
12
.pdata$_ZN8MyStructC1Ei
.pdata$_ZN8MyStructC1EOKS_
.pdata$_ZN8MyStructC1ERKS_
.pdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.text$_ZN8MyStructC1Ei
.text$_ZN8MyStructC1EOKS_
.text$_ZN8MyStructC1ERKS_
.text$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.xdata$_ZN8MyStructC1Ei
.xdata$_ZN8MyStructC1EOKS_
.xdata$_ZN8MyStructC1ERKS_
.xdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
MyStruct::MyStruct(int)
MyStruct::MyStruct(MyStruct&&)
MyStruct::MyStruct(MyStruct const&)
std::remove_reference<MyStruct&>::type&& std::move<MyStruct&>(MyStruct&)
Run Code Online (Sandbox Code Playgroud)
所以看来这种方法也行不通.
但是,如果目标类具有带有显式移动构造函数的成员,则隐式生成的移动构造函数对于目标类是可见的.即使用此代码:
#include <utility>
struct Foobar {
Foobar() = default;
Foobar(const Foobar&) = default;
Foobar(Foobar&&) {}
};
struct MyStruct {
MyStruct(int x) : x(x) {}
int x;
Foobar f;
};
int main() {
MyStruct s1(4);
MyStruct s2(s1);
MyStruct s3(std::move(s1));
return s1.x + s2.x + s3.x; // Make sure nothing is optimized away
}
Run Code Online (Sandbox Code Playgroud)
我会得到MyStruct移动ctor 的符号,但不会复制ctor,因为它似乎是完全隐含的.我认为如果可以的话,编译器会生成一个简单的内联移动ctor,如果它必须调用其他非平凡的移动ctors,则会产生一个非平凡的移动ctor.这仍然无法帮助我完成任务.
T.C*_*.C. 12
声明要存在的特殊成员函数MyStruct,但不要默认要检查的函数.假设您关心移动函数,并且还想确保移动构造函数是noexcept:
struct MyStruct {
MyStruct() = default;
MyStruct(const MyStruct&) = default;
MyStruct(MyStruct&&) noexcept; // no = default; here
MyStruct& operator=(const MyStruct&) = default;
MyStruct& operator=(MyStruct&&); // or here
};
Run Code Online (Sandbox Code Playgroud)
然后在类定义之外显式默认它们:
inline MyStruct::MyStruct(MyStruct&&) noexcept = default;
inline MyStruct& MyStruct::operator=(MyStruct&&) = default;
Run Code Online (Sandbox Code Playgroud)
如果默认函数被隐式定义为已删除,则会触发编译时错误.
正如Yakk指出的那样,如果编译器生成与否则通常无关紧要.
您可以检查类型是否是微不足道或不可移动构造
template< class T >
struct is_trivially_move_constructible;
template< class T >
struct is_nothrow_move_constructible;
Run Code Online (Sandbox Code Playgroud)
http://en.cppreference.com/w/cpp/types/is_move_constructible
局限性; 它还允许琐碎/不擅长复制结构.
| 归档时间: |
|
| 查看次数: |
3783 次 |
| 最近记录: |