将非const引用返回给私有向量成员的元素是不好的做法吗?

时间:2018-03-05 19:39:08

标签: c++ c++11

通过引用返回向量元素是不好的做法吗?

class X{
vector<Y> v;

public:
    Y& getRefFromVectorOfY(unsigned int index){
        retrun v.at(index);
    }
    void addToVectorOfY(Y y){
        v.push_back(move(y));
    }
};

虽然这是有效和干净的,但问题在于它打破了封装。如果v是一个向量,并且是一个类的私有成员,则调用者现在将拥有一个私有向量中的元素的引用,它们不仅可以从中读取,还可以分配给(覆盖)。

可以做到这一点

x.getRefFromVectorOfY(0).setNumber(7);  //not bad..actually good

x.getRefFromVectorOfY(0) = move(Y2);   //very bad!

甚至

Y3 = move(x.getRefFromVectorOfY(0));   //OMG

当然,我们可能会返回一个const&amp;相反,只允许const操作。

按值返回元素效率较低,因为它是副本。

如果 get 方法是将元素移出向量以按值返回,则向量将丢失数据完整性,因为它将不再存储已移出的数据(元素将是在向量内重置为默认状态...所以...仍然留在向量中但作为垃圾数据)。

我为什么要这样做?观点

如果您遵循零规则,并且您在类中有一个私有向量成员,则需要方便的方法来设置和设置向量。这提出了如何返回值的问题。

ref返回的问题是它破坏了封装,除非它是const ref。

那么,我应该只返回一个const ref强制任何值的设置来使用setVector方法吗?这个问题是有时你存储自定义类型...就像向量中的Y ..你需要访问Y的非const方法。而const&amp;保护vector元素不被向量中的重置或覆盖,它还可以防止调用者使用返回的元素非const方法。

所以如果我只返回const&amp; ...我不能做

x.getRefFromVectorOfY(0).setNumber(7);  //Y has a setNumber method

这将是一个问题。这将是一个问题,因为我不想在X类中重新实现Y的任何方法。这将是另一层间接和大量代码冗余。这反对返回一个const&amp;一般政策。在许多情况下不实用。

所以我必须根据返回值的常量覆盖,你不能这样做。

所以我必须有两个带有diff名称的函数,一个返回const&amp; ...而其他只返回一个&amp ;.那感觉很脏。

const Y& getConstRefFromVectorOfY(unsigned int index){
    retrun v.at(index);
}
Y& getRefFromVectorOfY(unsigned int index){
    retrun v.at(index);
}

修改

我添加了此表来总结问题目标

我希望X级的来电者能够有效地执行以下安全

  • MOD VECTOR
  • 矢量中的MOD元素
  • 在矢量中阅读元素

根据我的理解总结选项:

“ - ”是骗局,“+”是专业人士。

选项1 - 向量元素的返回副本

    MOD VECTOR
        + Can mod vector via class method addToVectorOfY
    MOD ELEMENT IN VECTOR
        - No way to mod Y element itself in vector without 
          indirection & redundancy (re-implementation of some Y methods)!!!  
          Because modifying returned copy does not modify what is in vector.
    READ ELEMENT IN VECTOR
        + Yes, inefficiently can read element data by looking at copy of element

选项2 - 返回向量元素的引用

   MOD VECTOR
        - Can mod vector in non-obious ways via returned ref to element. Breaks encapsulation.
          Dangerous and also redundant because class has setter method to mod vector.
        + Can mod vector via class method addToVectorOfY
    MOD ELEMENT IN VECTOR
        + Can call non-const methods of element returned
        - Some danger to the reference being invalid upon vector resize
    READ ELEMENT IN VECTOR
        + Yes, with maximum efficiency
        - Some danger to the reference being invalid upon vector resize

选项3 - 返回向量元素的const ref

   MOD VECTOR
        + Can mod vector via class method addToVectorOfY
    MOD ELEMENT IN VECTOR
        - No way to mod Y element itself in vector without 
          indirection & redundancy (re-implementation of some Y methods)!!! 
    READ ELEMENT IN VECTOR
        + Yes, with maximum efficiency
        - Some danger to the reference being invalid upon vector resize 

对于X级用户,是否有办法安全有效地完成所有3个工作?

2 个答案:

答案 0 :(得分:9)

嗯,std::vector's own operator[] returns a non-const reference,所以这本身就不错了。具体而言,这并没有打破封装。 - 矢量不应该封装其成员,它应该提供对它们的访问。

此外,您的所有3个示例都很好,而不仅仅是第一个。它不是&#34;非常糟糕&#34;也不是&#34; OMG&#34;。

话虽如此,请记住,std::vector的存储空间会随着其大小的变化而重新分配(至少在大小增加期间),因此它不能保证指针的有效性/引用它。

所以将引用(以及指针和不透明的迭代器)放在std::vector左右,这可能会导致调整大小。

答案 1 :(得分:1)

  

通过引用返回向量元素是不好的做法吗?

是的,总的来说?在大多数情况下,我认为如果您花时间将类的成员变量封装为private以控制对该变量的访问和操作,那么设计一个容易破坏该控件的成员函数会呈现第一步没有实际意义。根据用例的不同,这可能并非总是如此,但是在这里你提出的问题是如此抽象,以至于很难给出具体的答案。我在帖子中可以识别的唯一真正问题是:

  

按值返回元素效率较低,因为它是副本,效率较低。

我想这里要问的真正问题是,在保持对成员变量的更大访问控制与更直接访问底层内存之间存在有意义的,可衡量的性能差异,以便您可以更快地操作它?你是对的,通过引用返回在某些方面更有效,但这实际上是否会对你的特定代码产生实际的影响?

此外,您需要为要公开的私有成员变量维护什么级别的数据完整性也很重要。 einpoklum非常重视许多标准容器遵循这种范例。他们对存储在容器中的值没有期望,只是他们保持对它们所拥有的内存的分配/删除的控制。您的班级可能对成员值采用的值有更强的控制要求。例如,如果该向量中的所有数据元素都必须是非负数,那么通过公开对该内存的引用,您将无法使该类具有这种数据完整性保证。它实际上只取决于需求,虽然我更喜欢根据需要有选择地释放对成员变量的控制的范例,而不是提供完全访问权限,并在你想要添加额外保证时慢慢取消它。