Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在构造函数初始化列表上移动共享\u ptr_C++_C++11_Optimization_Move_Move Semantics - Fatal编程技术网

C++ 在构造函数初始化列表上移动共享\u ptr

C++ 在构造函数初始化列表上移动共享\u ptr,c++,c++11,optimization,move,move-semantics,C++,C++11,Optimization,Move,Move Semantics,最近我看到了一些这样的代码示例,其中std::move用于构造函数初始化列表(而不是move构造函数) A类{ 公众: A(std::shared_ptr res):myRes(std::move(res)){ // ... } 私人: std::共享\u ptr myRes; } 我得到的信息是,这项建设是出于优化的原因。就我个人而言,我尽可能少地使用std::move。我以演员身份威胁他们(正如Scott Meyers所说),并且只在调用方代码中威胁他们(唯一的例外是move构造函数)。对

最近我看到了一些这样的代码示例,其中std::move用于构造函数初始化列表(而不是move构造函数)

A类{
公众:
A(std::shared_ptr res):myRes(std::move(res)){
// ...
}
私人:
std::共享\u ptr myRes;
}

我得到的信息是,这项建设是出于优化的原因。就我个人而言,我尽可能少地使用std::move。我以演员身份威胁他们(正如Scott Meyers所说),并且只在调用方代码中威胁他们(唯一的例外是move构造函数)。对我来说,这看起来像是某种模糊处理或微观优化,但也许我错了。这是真的吗?编译器没有产生更快的代码,没有STD::Stest.t/P>< P>我考虑了一个丢失的代码> STD::MOVER()/<代码>,其中一个非平凡对象可以被移动,但是编译器不能检测到这是代码中的错误。也就是说,构造函数中的
std::move()
是必需的:显然,调用构造函数的临时对象即将超出范围,也就是说,它可以安全地从中移动。另一方面,从参数构造成员变量并不是可以省略副本的情况之一。也就是说,编译器必须创建一个副本,这对于
std::shared_ptr
来说当然不是很昂贵,但它也不是免费的。特别是,需要同步更新的参考计数。差异是否可以测量是另一个问题。运行一个简单的基准(见下文)似乎意味着性能确实有所提高。我得到的结果通常如下所示:

// clang:
copy: 440
move: 206
copy: 414
move: 209
// gcc:
copy: 361
move: 167
copy: 335
move: 170
请注意,在此上下文中,您是成员构造函数的调用方!正确的说法是,
std::move(res)
只是编写强制转换的一种奇特方式(它取代了
静态强制转换(res)
)。但是,在对象即将超出范围但被复制的地方使用它是至关重要的。从语义上讲,
std::move()
的使用在许多情况下都是不相关的(它仅在处理可移动但不可复制的类型时才在语义上相关)。避免不必要的拷贝是一项重要的性能改进和
std::move()
有助于在编译器无法推断是否可以或不允许这样做的情况下这样做:特定情况下,编译器甚至可以自行检测到移动是安全的,但不允许用移动替换副本。如果编译器能在这些情况下警告缺少
std::move()
,那就太好了

#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <memory>
#include <ostream>
#include <vector>

class timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point d_start;
public:
    timer(): d_start(clock::now()) {}
    std::ostream& print(std::ostream& out) const {
        using namespace std::chrono;
        return out << duration_cast<microseconds>(clock::now() - this->d_start).count();
    }
};

std::ostream& operator<< (std::ostream& out, timer const& t)
{
    return t.print(out);
}

struct ResCopy
{
    std::shared_ptr<unsigned int> d_sp;
    ResCopy(std::shared_ptr<unsigned int> sp): d_sp(sp) {}
    unsigned int value() const { return *this->d_sp; }
};

struct ResMove
{
    std::shared_ptr<unsigned int> d_sp;
    ResMove(std::shared_ptr<unsigned int> sp): d_sp(std::move(sp)) {}
    unsigned int value() const { return *this->d_sp; }
};

template <typename Res>
void measure(char const* name, std::vector<std::shared_ptr<unsigned int>> const& v)
{
    timer t;
    unsigned long value(0);
    for (int c(0); c != 100; ++c) {
        for (std::size_t i(0), end(v.size()); i != end; ++i) { 
            value += Res(v[i]).value();
        }
    }
    std::cout << name << ": " << t << '\n';
}

int main()
{
    std::vector<std::shared_ptr<unsigned int>> v;
    std::generate_n(std::back_inserter(v), 100,
                    []{ return std::shared_ptr<unsigned int>(new unsigned int(std::rand())); });

    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
班级计时器
{
typedef std::chrono::高分辨率时钟;
时钟:开始的时间点;
公众:
计时器():d_开始(时钟::现在()){}
std::ostream&print(std::ostream&out)常数{
使用名称空间std::chrono;
返回d_start)。计数();
}
};
std::ostream&operator_sp;}
};
结构重新移动
{
std::共享_ptr d_sp;
ResMove(std::shared_ptr sp):d_sp(std::move(sp)){
无符号int value()常量{return*this->d_sp;}
};
模板
无效度量(字符常量*名称,标准::向量常量&v)
{
定时器t;
无符号长值(0);
for(int c(0);c!=100;++c){
对于(std::size_t i(0),end(v.size());i!=end;++i){
value+=Res(v[i])。value();
}
}

std::我是否认为这样做的目的是为了避免引用计数器的原子增量。这也是一个精确表达意图的问题,也是一个相当常见的模式(传递值,然后移动局部参数)。可能重复@User207933我不确定这是否是该特定问题的完全重复。主要关注的是在移动构造函数中移动数据成员;这与此问题中的问题不同。不过,性能部分在那里得到了部分回答。公平地说,我撤回了投票,但我将从我认为这与性能方面有关。相关:
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <memory>
#include <ostream>
#include <vector>

class timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point d_start;
public:
    timer(): d_start(clock::now()) {}
    std::ostream& print(std::ostream& out) const {
        using namespace std::chrono;
        return out << duration_cast<microseconds>(clock::now() - this->d_start).count();
    }
};

std::ostream& operator<< (std::ostream& out, timer const& t)
{
    return t.print(out);
}

struct ResCopy
{
    std::shared_ptr<unsigned int> d_sp;
    ResCopy(std::shared_ptr<unsigned int> sp): d_sp(sp) {}
    unsigned int value() const { return *this->d_sp; }
};

struct ResMove
{
    std::shared_ptr<unsigned int> d_sp;
    ResMove(std::shared_ptr<unsigned int> sp): d_sp(std::move(sp)) {}
    unsigned int value() const { return *this->d_sp; }
};

template <typename Res>
void measure(char const* name, std::vector<std::shared_ptr<unsigned int>> const& v)
{
    timer t;
    unsigned long value(0);
    for (int c(0); c != 100; ++c) {
        for (std::size_t i(0), end(v.size()); i != end; ++i) { 
            value += Res(v[i]).value();
        }
    }
    std::cout << name << ": " << t << '\n';
}

int main()
{
    std::vector<std::shared_ptr<unsigned int>> v;
    std::generate_n(std::back_inserter(v), 100,
                    []{ return std::shared_ptr<unsigned int>(new unsigned int(std::rand())); });

    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
}