代码之家  ›  专栏  ›  技术社区  ›  alfC

移动引用重载以访问容器中的元素?[重复]

  •  1
  • alfC  · 技术社区  · 7 年前

    标准C++容器只提供一个版本 operator[] 对于像这样的容器 vector<T> deque<T> .它返回一个 T& (除了 vector<bool> ,我将忽略),这是一个左值。这意味着在这样的代码中,

    vector<BigObject> makeVector();       // factory function
    
    auto copyOfObject = makeVector()[0];  // copy BigObject
    

    copyOfObject 将被复制构建。鉴于此 makeVector() 返回一个右值 vector ,这似乎是合理的预期 复制对象 被建造。

    如果 操作员[] 对于这样的容器,对于右值和左值对象重载 操作员[] 对于右值,容器可以返回右值引用,即右值:

    template<typename T>
    container {
    public:
        T& operator[](int index) &;       // for lvalue objects
        T&& operator[](int index) &&;     // for rvalue objects
    ...
    };
    

    那样的话 复制对象 将被建造。

    总的来说,这种超载是个坏主意,有什么原因吗?C++14中的标准容器没有这样做有什么原因吗?

    0 回复  |  直到 11 年前
        1
  •  3
  •   T.C. Yksisarvinen    11 年前

    将评论转换为答案:

    这种方法没有本质上的错误;类成员访问遵循类似的规则( E1.E2 是一个xvalue if E1 是一个右值 E2 命名非静态数据成员,而不是引用,请参见[expr.ref]/4.2),容器中的元素在逻辑上与非静态数据成员相似。

    这是一个重要的问题 std::vector 或其他标准容器,它可能会破坏一些遗留代码。考虑:

    void foo(int &);
    std::vector<int> bar();
    
    foo(bar()[0]);
    

    如果 operator[] 在右值向量上返回一个xvalue。或者——可以说更糟——如果有 foo(const int &) 重载时,它将以静默方式开始调用该函数。

    此外,在容器中返回一组元素,而只使用一个元素已经相当低效了。有争议的是,这样做的代码可能根本不太关心速度,因此性能的微小改进不值得引入一个潜在的突破性更改。

        2
  •  0
  •   Arsen Y.M.    11 年前

    我认为,如果移出其中一个元素,容器将处于无效状态,我认为需要允许这种状态。第二,如果你需要它,你能不能像这样调用新对象的移动构造函数:

    T copyObj = std::move(makeVector()[0]);

    更新:

    最重要的一点是,在我看来,容器本质上就是容器,所以它们无论如何都不应该修改其中的元素。它们只提供存储、迭代机制等。