鉴于一个类实际上是可移动的,手动实现移动构造函数和移动类的赋值运算符很快变得乏味.
我想知道什么时候这样做实际上是一个沉重,沉重,过早的优化?
例如,如果一个类只有普通的POD数据或者它们自己有移动构造函数和移动赋值运算符定义的成员,那么我猜测编译器将只是优化该批次的狗屎(在POD的情况下)和否则使用成员的移动构造函数和移动赋值运算符.
但这有保证吗?在什么情况下,我应该想到明确需要实现一个移动构造函数和移动赋值操作符?
编辑:正如他在回答评论下面提到的尼科尔流星锤/sf/answers/697627381/,与Visual Studio 11 Beta版(之前)没有转移构造函数或移动赋值操作符是不断自动生成.参考:http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
可能重复:
移动对象有什么用处?
在调用std::move并将结果传递给函数之后,通常必须假定稍后访问移动的对象将导致未定义的行为.
是否有工具可以检测这些访问并警告您.例如:
{
Widget w;
foo(std::move(w));
// w may be undefined at this point
w.doSomething(); // WARN
}
Run Code Online (Sandbox Code Playgroud)
至少,gcc 4.7.2并且clang 3.2与-Wall不抱怨.
更新:回顾这个问题,关键点是编译器无法确定对象在移动后是否仍然有效.如果提议N4034:Destructive Move被接受,我希望编译器有更多选项(但只有在移动是破坏性的时候).
具有引用成员变量的类的复制赋值是禁止的,因为您无法重新分配引用.但是移动分配怎么样?我只是尝试了move它,当然,当我只想移动引用本身时,它会破坏源对象:
class C
{
public:
C(X& x) : x_(x) {}
C(C&& other) : x_(std::move(other.x_)) {}
C& operator=(C&& other)
{
x_ = std::move(other.x_);
}
private:
X& x_;
};
X y;
C c1(y);
X z;
C c2(z);
c2 = c1; // destroys y as well as z
Run Code Online (Sandbox Code Playgroud)
我不应该只是实施移动分配并坚持使用移动构造吗?这swap(C&, C&)很难实现.
考虑以下类.
struct with_copy {
with_copy() = default;
with_copy(with_copy const&) {}
with_copy& operator=(with_copy const&) { return *this; }
};
struct foo {
with_copy c;
std::unique_ptr<int> p;
};
Run Code Online (Sandbox Code Playgroud)
with_copy有一个拷贝构造函数?是.它是明确定义的.with_copy有一个移动构造函数?不可以.显式复制构造函数阻止生成它.with_copy有删除的移动构造函数?不.没有移动构造函数与删除构造函数不同.删除的移动构造函数会尝试将格式错误而不是退化移动到副本.with_copy复制吗?是.其复制构造函数用于复制.with_copy可移动的?是.它的复制构造函数用于移动.......现在是棘手的.
foo有一个拷贝构造函数?是.它有一个删除的,因为它的默认定义将由于调用unique_ptr已删除的复制构造函数而格式不正确.foo有一个移动构造函数?GCC说是的,clang说没有.foo有删除的移动构造函数?海湾合作委员会和铿锵声说不.foo复制吗?不会.它的复制构造函数被删除.foo可移动的?GCC说是的,clang说没有.(当考虑赋值而不是构造时,行为类似.)
据我所知,海湾合作委员会是正确的.foo应该有一个移动构造函数,在每个成员上执行移动,在这种with_copy情况下退化为副本.Clang的行为似乎很荒谬:我有一个有两个可移动成员的聚合体,但我的聚合物是一个不可移动的砖块.
谁是对的?
c++ user-defined-functions implicit-declaration move-semantics c++11
我有以下Singleton策略类实现:
template <typename T>
class Singleton
{
Singleton(){}; // so we cannot accidentally delete it via pointers
Singleton(const Singleton&) = delete; // no copies
Singleton& operator=(const Singleton&) = delete; // no self-assignments
Singleton(Singleton&&) = delete; // WHY?
Singleton& operator=(Singleton&&) = delete; // WHY?
public:
static T& getInstance() // singleton
{
static T instance; // Guaranteed to be destroyed.
// Instantiated on first use.
// Thread safe in C++11
return instance;
}
};
Run Code Online (Sandbox Code Playgroud)
然后我通过奇怪的重复模板模式(CRTP)使用
class Foo: public Singleton<Foo> // now Foo …Run Code Online (Sandbox Code Playgroud) 假设一个具有以下原型的功能
template<typename T>
std::unique_ptr<T> process_object(std::unique_ptr<T> ptr);
Run Code Online (Sandbox Code Playgroud)
该函数可以返回传递给它的对象(移动版本)或完全不同的对象.
使用此函数是合法的C++如下吗?
std::unique_ptr<Widget> pw(new Widget());
pw = process_object(std::move(pw));
Run Code Online (Sandbox Code Playgroud)
如果我没记错的话,有一个C/C++规则禁止在一个完整的表达式中多次修改一个对象.这条规则适用于此吗?如果是的话,有没有办法在一行中以不同的方式表达这个习语?
如果一个人std::unique_ptr被鄙视取代std::auto_ptr怎么办?
特别是std::vector与其相关的是,类型noexcept在可能的情况下是可移动的.
所以在声明= default像in 的移动构造函数时
struct Object1
{
Object1(Object1 &&other) = default;
};
Run Code Online (Sandbox Code Playgroud)
std::is_nothrow_move_constructible<Object1>::value将是true每个成员(0在这里)Object1是nothrow-move-constructible,这在这里得到解答.
然而,如果仅声明移动复制构造函数,然后= default在以下代码中进行定义,会发生什么?
struct Object2
{
Object2(Object2 &&other);
};
Object2::Object2(Object2 &&other) = default;
Run Code Online (Sandbox Code Playgroud)
随着G ++ 4.9.2 std::is_nothrow_move_constructible<Object2>::value是false,我要纪念这两个声明和定义noexcept,使其true.
现在我感兴趣的是实际规则是什么.特别是因为有效的现代C++中的第22项(Scott Meyers)似乎通过建议像我一样实现了pimpl-idiom移动构造函数来提供错误的建议Object2.
所以,这提供了预期的输出:
void f(std::string&& s)
{
s += " plus extra";
}
int main(void)
{
std::string str = "A string";
f( std::move(str) );
std::cout << str << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
字符串加上额外的
也就是说,当我在Ideone上运行它时,它可以工作,但它是UB吗?在调用之前和之后添加额外的字符串初始化f没有改变任何东西.
据我所知,在C++ 11中有效实现构造函数的两种常用方法是使用其中两种
Foo(const Bar& bar) : bar_{bar} {};
Foo(Bar&& bar) : bar_{std::move(bar)} {};
Run Code Online (Sandbox Code Playgroud)
或者只是一个时尚的
Foo(Bar bar) : bar_{std::move(bar)} {};
Run Code Online (Sandbox Code Playgroud)
使用第一个选项产生最佳性能(例如,在左值的情况下希望是单个副本,在rvalue的情况下希望单个移动),但是对于N个变量需要2个N重载,而第二个选项只需要一个函数通过左值时的额外动作.
在大多数情况下,这不应该产生太大的影响,但肯定两种选择都不是最佳选择.但是,也可以执行以下操作:
template<typename T>
Foo(T&& bar) : bar_{std::forward<T>(bar)} {};
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是允许可能不需要的类型的变量作为bar参数(这是我确信使用模板专门化很容易解决的问题),但无论如何,性能是最佳的,代码随着变量的数量线性增长.
为什么没有人为此目的使用像forward这样的东西?这不是最优化的方式吗?
在 C++ 中,是否可以从我以后不再需要的地图中窃取资源?更准确地说,假设我有一个std::mapwithstd::string键,我想通过map使用std::move. 请注意,对键的这种写访问会破坏 的内部数据结构(键的顺序),map但之后我不会使用它。
问题:我可以在没有任何问题的情况下执行此操作,还是会导致意外错误,例如在析构函数中出现意外错误,map因为我std::map以非预期的方式访问它?
这是一个示例程序:
#include<map>
#include<string>
#include<vector>
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
std::vector<std::pair<std::string,double>> v;
{ // new scope to make clear that m is not needed
// after the resources were stolen
std::map<std::string,double> m;
m["aLongString"]=1.0;
m["anotherLongString"]=2.0;
//
// now steal resources
for (auto &p : m) {
// according to my IDE, p has type
// std::pair<const …Run Code Online (Sandbox Code Playgroud) c++ ×10
move-semantics ×10
c++11 ×9
noexcept ×1
optimization ×1
pimpl-idiom ×1
singleton ×1
warnings ×1