VS2013:优化具有向量成员的类的移动语义的潜在问题?

马克

我在VS2013上编译了以下代码(使用“发布”模式优化),但沮丧地发现的程序集与std::swap(v1,v2)并不相同std::swap(v3,v4)

#include <vector>
#include <iterator>
#include <algorithm>

template <class T>
class WRAPPED_VEC
{
public:
    typedef T value_type;
    void push_back(T value) { m_vec.push_back(value); }

    WRAPPED_VEC() = default;

    WRAPPED_VEC(WRAPPED_VEC&& other) : m_vec(std::move(other.m_vec)) {}

    WRAPPED_VEC& operator =(WRAPPED_VEC&& other)
    {
        m_vec = std::move(other.m_vec);
        return *this;
    }

private:
    std::vector<T> m_vec;
};


int main (int, char *[])
{
    WRAPPED_VEC<int> v1, v2;
    std::generate_n(std::back_inserter(v1), 10, std::rand);
    std::generate_n(std::back_inserter(v2), 10, std::rand);
    std::swap(v1, v2);

    std::vector<int> v3, v4;
    std::generate_n(std::back_inserter(v3), 10, std::rand);
    std::generate_n(std::back_inserter(v4), 10, std::rand);
    std::swap(v3, v4);

    return 0;
}

std::swap(v3, v4)语句变为“完美”的程序集。我如何才能达到相同的效率std::swap(v1, v2)

霍华德·辛南特(Howard Hinnant)

这里有几点要说明。

1.如果您不确定您的调用方式swap是否等同于“正确”的调用方式swap,则应始终使用“正确”的方式:

using std::swap;
swap(v1, v2);

2.在程序swap集中查找诸如调用之类的一种非常方便的方法是将调用本身置于测试函数中。这样可以很容易地隔离程序集:

void
test1(WRAPPED_VEC<int>& v1, WRAPPED_VEC<int>& v2)
{
    using std::swap;
    swap(v1, v2);
}

void
test2(std::vector<int>& v1, std::vector<int>& v2)
{
    using std::swap;
    swap(v1, v2);
}

就目前而言,test1将调用std::swap如下所示的内容:

template <class T>
inline
swap(T& x, T& y) noexcept(is_nothrow_move_constructible<T>::value &&
                          is_nothrow_move_assignable<T>::value)
{
    T t(std::move(x));
    x = std::move(y);
    y = std::move(t);
}

而且速度很快。它将使用WRAPPED_VEC的move构造函数和move赋值运算符。

但是vectorswap甚至更快:它交换vector的3个指针,并且如果std::allocator_traits<std::vector<T>::allocator_type>::propagate_on_container_swap::value为true(不是),那么还将交换分配器。如果它是错误的(并且是),并且两个分配器相等(并且它们是),那么一切正常。否则会发生未定义的行为。

要使性能test1test2性能相同,您需要:

friend
void
swap(WRAPPED_VEC<int>& v1, WRAPPED_VEC<int>& v2)
{
    using std::swap;
    swap(v1.m_vec, v2.m_vec);
}

需要指出的一件事是:

就您而言,在您始终使用的情况下,std::allocator<T>friend功能始终是一个胜利。但是,如果您的代码允许其他分配器(可能具有状态的分配器,它们可能比较不相等,并且可能具有propagate_on_container_swap::valuefalse std::allocator<T>)(那么也是如此),则swapfor的这两种实现会WRAPPED_VEC有所不同:

1.如果您依赖std::swap,那么您会受到性能上的打击,但是您将永远不可能陷入不确定的行为。移动构造vector始终是明确定义的,且为O(1)。移动分配vector始终是明确定义的,可以是O(1)或O(N),并且可以是noexcept(true)或noexcept(false)。

如果propagate_on_container_move_assignment::value为false,并且移动分配中涉及的两个分配器不相等,则vector移动分配将变为O(N)和noexcept(false)。因此,swap使用vector移动分配将继承这些特征。但是,无论如何,该行为始终是明确定义的。

2.如果你超载swapWRAPPED_VEC,从而依靠swap过载vector,那么你暴露自己的未定义行为的可能性,如果该分配器比较不平等,有propagate_on_container_swap::value等于假。但是,您获得了潜在的性能胜利。

与往常一样,需要在工程上进行权衡。这篇文章旨在提醒您这些权衡的性质。

PS:以下评论纯属文体风格。所有类别类型的大写名称通常被认为是较差的样式。传统上所有大写名称都保留用于宏。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

VS2013:优化具有向量成员的类的移动语义的潜在问题?

来自分类Dev

具有 const 向量成员的类的复制构造函数

来自分类Dev

具有向量成员的对象的破坏

来自分类Dev

无法访问类的向量成员

来自分类Dev

指向具有移动语义的成员函数的指针

来自分类Dev

C ++ 03通过构造函数将向量移动到类成员中(移动语义)

来自分类Dev

如何为具有参考的类模板支持移动语义

来自分类Dev

如何为具有参考的类模板支持移动语义

来自分类Dev

VS2013有一些问题

来自分类Dev

具有常量成员的默认构造函数

来自分类Dev

具有变量成员的树上的Haskell树折叠

来自分类Dev

内联成员缺少返回时没有错误(VS2013)

来自分类Dev

模板类VS2013的异常行为

来自分类Dev

如何使用多态从基类访问派生类向量成员?

来自分类Dev

如何使用多态性从基类访问派生类向量成员?

来自分类Dev

具有转换运算符的C ++ 11 Template Wrapper类-移动语义

来自分类Dev

具有移动语义的RAII类中的默认构造函数应该做什么?

来自分类Dev

如何在类模板的构造函数中初始化向量成员变量

来自分类Dev

如何在类定义中初始化向量成员变量?

来自分类Dev

从具有移动语义或返回值优化的函数返回值,但不从复制构造函数返回

来自分类Dev

如何修改向量成员的值?

来自分类Dev

内联成员缺少返回的错误(VS2013)

来自分类Dev

团队成员未出现在VS2013中

来自分类Dev

空行或带符号的行在VS2013中仅具有较小的字体大小

来自分类Dev

VS2013创建几个具有不同类的dll文件以与谷物进行序列化

来自分类Dev

初始化类的静态常量成员,其中成员是私有类型?

来自分类Dev

是否有用于检查向量成员资格的R函数?

来自分类Dev

gdb“静态字段值已被优化”,用于具有非类型参数的类模板的静态成员

来自分类Dev

具有潜在未定义索引的向量访问

Related 相关文章

  1. 1

    VS2013:优化具有向量成员的类的移动语义的潜在问题?

  2. 2

    具有 const 向量成员的类的复制构造函数

  3. 3

    具有向量成员的对象的破坏

  4. 4

    无法访问类的向量成员

  5. 5

    指向具有移动语义的成员函数的指针

  6. 6

    C ++ 03通过构造函数将向量移动到类成员中(移动语义)

  7. 7

    如何为具有参考的类模板支持移动语义

  8. 8

    如何为具有参考的类模板支持移动语义

  9. 9

    VS2013有一些问题

  10. 10

    具有常量成员的默认构造函数

  11. 11

    具有变量成员的树上的Haskell树折叠

  12. 12

    内联成员缺少返回时没有错误(VS2013)

  13. 13

    模板类VS2013的异常行为

  14. 14

    如何使用多态从基类访问派生类向量成员?

  15. 15

    如何使用多态性从基类访问派生类向量成员?

  16. 16

    具有转换运算符的C ++ 11 Template Wrapper类-移动语义

  17. 17

    具有移动语义的RAII类中的默认构造函数应该做什么?

  18. 18

    如何在类模板的构造函数中初始化向量成员变量

  19. 19

    如何在类定义中初始化向量成员变量?

  20. 20

    从具有移动语义或返回值优化的函数返回值,但不从复制构造函数返回

  21. 21

    如何修改向量成员的值?

  22. 22

    内联成员缺少返回的错误(VS2013)

  23. 23

    团队成员未出现在VS2013中

  24. 24

    空行或带符号的行在VS2013中仅具有较小的字体大小

  25. 25

    VS2013创建几个具有不同类的dll文件以与谷物进行序列化

  26. 26

    初始化类的静态常量成员,其中成员是私有类型?

  27. 27

    是否有用于检查向量成员资格的R函数?

  28. 28

    gdb“静态字段值已被优化”,用于具有非类型参数的类模板的静态成员

  29. 29

    具有潜在未定义索引的向量访问

热门标签

归档