c++ 参考的重载,而不是唯一的pass-by-value std :: move?

看来关于C 0x的右值的主要建议是添加移动构造函数和移动运算符到你的类,直到编译器默认实现它们。

但是等待是一个失去的策略,如果你使用VC10,因为自动生成可能不会在这里,直到VC10 SP1,或在最坏的情况下,VC11。可能,等待这一点将以几年来衡量。

这里是我的问题。写所有这些重复的代码是没有乐趣。看起来很不愉快。但这是一个很好的负担,对于那些被认为缓慢的类。不是为数百,如果不是数千,较小的类。

:: sighs :: C 0x应该让我写更少的代码,而不是更多!

然后我有一个想法。由许多人共享,我猜。

为什么不通过价值传递一切?不会std ::移动复制elision使这几乎最优?

示例1 – 典型的Pre-0x构造函数

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // single copy
OurClass(SomeClass());  // single copy

缺点:对于右值的浪费的副本。

示例2 – 推荐C 0x?

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // zero copies, one move
OurClass(SomeClass());  // zero copies, one move

优点:大概是最快的。
缺点:很多代码!

示例3 – 按值传递std :: move

OurClass::OurClass(SomeClass obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy, one move
OurClass(std::move(o)); // zero copies, two moves
OurClass(SomeClass());  // zero copies, one move

优点:没有额外的代码。
缺点:1&如果SomeClass没有移动构造函数,性能将受到很大的影响。

你怎么看?它是否正确?与代码缩减的优势相比,所发生的移动是否是一个普遍可接受的损失?

最佳答案
我对你的问题感兴趣,因为我是新的话题,并做了一些研究。
让我提出结果。

首先,你的叹息。

enter code here::sighs:: C++0x was supposed to let me write less code, not more!

它也是应该是给你一个更好的控制代码。而它是。
我会坚持一个额外的构造函数:

OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

我个人喜欢在复杂和重要的情况下的冗长,因为它保持我和可能的读者我的代码警告。

取例如C风格的cast(T *)pT和C标准的static_cast * T(pT)
更冗长 – 但向前迈出了一大步。

第二,我对你的例子3,最后一个测试用例有点怀疑。我认为可能有另一个移动构造函数从右值创建传值的参数。所以我在我的新VS2010中创建了一些快速项目,并得到一些澄清。我将在这里发布代码以及结果。

来源:

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <utility>
#include <iostream>

class SomeClass{
    mutable int *pVal;
public:
    int Val() const { return *pVal; };
    SomeClass(int val){
        pVal = new int(val);
        std::cout << "SomeClass constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    SomeClass(const SomeClass& r){
        pVal = new int(r.Val());
        std::cout << "SomeClass copy constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }   
    SomeClass(const SomeClass&& r){
        pVal = r.pVal;
        r.pVal = 0;
        std::cout << "SomeClass move constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    ~SomeClass(){
        if(pVal)
            delete pVal;
        std::cout << "SomeClass destructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
};

class OtherClass{
    SomeClass sc;
public:
    OtherClass(int val):sc(val){
    }

注意这个部分:

#if 1
    OtherClass(SomeClass r):sc(std::move(r)){
    }
#else
    OtherClass(const SomeClass& r):sc(r){
    }   
    OtherClass(const SomeClass&& r):sc(std::move(r)){
    }
#endif

… …

    int Val(){ return sc.Val(); }
    ~OtherClass(){
    }
};

#define ECHO(expr)  std::cout << std::endl << "line " << __LINE__ << ":\t" #expr ":" << std::endl; expr

int _tmain(int argc, _TCHAR* argv[])
{
    volatile int __dummy = 0;
    ECHO(SomeClass o(10));

    ECHO(OtherClass oo1(o));            
    __dummy += oo1.Val();
    ECHO(OtherClass oo2(std::move(o))); 
    __dummy += oo2.Val();
    ECHO(OtherClass oo3(SomeClass(20)));  
    __dummy += oo3.Val();

    ECHO(std::cout << __dummy << std::endl);
    ECHO(return 0);
}

正如你所注意到的,有一个编译时间开关,允许我测试这两种方法。

现在,它的时间来看结果。

结果最好在文本比较模式下查看,在左边你可以看到#if 1编译,这意味着我们检查建议的解决方法,右侧 – #if 0,这意味着我们检查“kosher”方式描述c 0x! alt text

我错了怀疑编译器做蠢事,它保存了额外的移动构造函数在第三个测试用例。

但是说实话,我们必须考虑在建议的解决方法中调用另外两个析构函数,但这是一个小缺陷,考虑到如果在被销毁的对象上发生了移动,则不应该执行任何动作。不过,这是很好知道。

在任何情况下,我不会离开的点,最好在包装类中写另一个构造函数。这只是几行,因为所有繁琐的工作已经在SomeClass中完成,必须有一个移动构造函数。

感谢一个有趣的话题!
问候,
狮子座。

转载注明原文:c++ 参考的重载,而不是唯一的pass-by-value std :: move? - 代码日志