C++

不同的编译器在处理C++构造函数的那些坑

Posted by Remilia Scarlet on July 2, 2019

关于移动构造函数

以下这段代码在不同的编译器里处理方式不同

void insert(std::map<std::string,std::string> &m,const _Key &s, const _Value &value)
{
      m.insert({ s,_Value(value) });//_Value为自定义类
}

在vs里这里的pair临时对象{ s,_Value(value) }会以右值引用的方式传递给insert函数,而在g++和clang编译器里这里会调用一系列的拷贝构造函数(包括_Value(const _Value &rhs)和constexpr std::pair<_T1, _T2>::pair((const std::pair<_T1, _T2>&) )

如果这里是希望编译器一定能够调用移动构造函数最好写成下面这种形式

void insert(std::map<std::string,std::string> &m,const _Key &s, const _Value &value)
{
    auto p = std::make_pair( s,_Value(value) );
    m.insert(std::move(p));
}

后来又测试了一下,发现写成临时对象也是可以的,不过不能使用花括号初始化pair

void insert(std::map<std::string,std::string> &m,const _Key &s, const _Value &value)
{
    m.insert(std::make_pair( s,_Value(value) ));
}

写成这样也不会有问题,似乎是编译器在处理{}初始化pair时会产生一个额外的对象

最后的最后,我去反汇编了一下这段代码,写成花括号形式的初始化在在不同版本的GCC里调用的构造函数也不同。

gcc7.3以前的版本会编译成

call std::map, std::allocator >, std::__cxx11::basic_string, std::allocator >, std::less, std::allocator > >, std::allocator, std::allocator > const, std::__cxx11::basic_string, std::allocator > > > >::insert(std::pair, std::allocator > const, std::__cxx11::basic_string, std::allocator > > const&)

而gcc7.3以后的版本会编译成

call std::map, std::allocator >, std::__cxx11::basic_string, std::allocator >, std::less, std::allocator > >, std::allocator, std::allocator > const, std::__cxx11::basic_string, std::allocator > > > >::insert(std::pair, std::allocator > const, std::__cxx11::basic_string, std::allocator > >&&)

总结:为了让编译器能够显式的调用移动构造函数,还是手写成右值引用的形式比较好


| 访问量: