如何返回向量的“只读”副本

Posted

技术标签:

【中文标题】如何返回向量的“只读”副本【英文标题】:How to return a 'read-only' copy of a vector 【发布时间】:2010-03-17 20:44:37 【问题描述】:

我有一个具有私有属性向量 rectVec 的类;

class A 
private:
   vector<Rect> rectVec;
;

我的问题是如何返回我的 Vector 的“只读”副本? 我正在考虑这样做:

class A 
public:
  const vect<Rect>& getRectVec()  return rectVect; 

这是正确的方法吗? 我在想这样可以防止被调用者修改向量(在向量中添加/删除Rect),那么向量里面的Rect呢?

【问题讨论】:

这听起来有点混乱。如果您制作副本,为什么它是否是只读的很重要?如果您想要对原始数据进行只读访问,那么您就不需要制作副本。 【参考方案1】:

这是正确的方法,尽管您可能还想创建函数 const

class A 
public:
  const vect<Rect>& getRectVec() const  return rectVect;                            
;

这样人们就可以使用const A 对象调用getRectVec

【讨论】:

这似乎不适用于const vector&lt;unique_ptr&lt;T&gt;&gt;&amp;。有没有办法返回一个只读的向量/STL容器,它的T*unique_ptr&lt;T&gt;对象不能被修改,向量也不能被修改,即。 e.一个完全只读的向量?当然,项目和向量本身应该在持有类中是可更改的。【参考方案2】:

这是正常的方式。 const 表示“你不能修改它”。它也适用于容器内的元素。

一个简单的测试:

#include <vector>

typedef std::vector<int> int_vec;

struct foo

    const int_vec& get(void)
    
        return v;
    

    int_vec v;
;

int main(void)

    foo f;
    f.v.push_back(1);
    f.v.push_back(2);
    f.v.push_back(3);

    f.get()[0] = 2; // nope


const_cast 可用于剥离 const,但如果您通过它修改变量,则最终会出现未定义的行为:

int_vec& v = const_cast<int_vec&>(f.get()); // this is okay
v[0] = 0; // but now we've entered undefined behavior

【讨论】:

如果您必须防止 const 被丢弃,并且不介意(巨大的)性能损失,您可以返回向量的副本。这样,调用者可以以他们想要的任何方式更改它,而不会影响私有向量。只需按值而不是引用返回。 “以未定义的行为结束”:不完全是,因为 v 首先没有声明为 const。 @Arkadiy:它已经通过导致未定义的行为得到保护。没有人应该说或做更多的事情;欲入未定界,必亡。 @GMan 正如 AraK 所说,如果将指向/引用的对象声明为 const,则只有 UB 才能抛弃 const-ness。丢弃指针上的 const 或对本身不是 const 的对象的引用是完美定义的,尽管通常表明设计不好。 可能是糟糕的设计。为了与糟糕的设计进行交互,也可能需要它。【参考方案3】:

我知道这是一篇相当老的帖子,但在搜索“c++ 只读向量”时,它是谷歌搜索结果中排名靠前的结果之一。这就是为什么我想发布我的方法。

如果您希望容器本身是 const 而不是它的元素,您可以使用类似于此的方法:

template<class Container>
class Enumerable

public:
    Enumerable(Container& container) : _container(container) 

    auto begin() const  return _container.begin(); 
    auto end() const  return _container.end(); 

    const Container& GetContainer() const  return _container; 
    const Container* operator->() const  return &_container; 

private:
    Container& _container;
;

这样,您可以迭代容器并修改其元素,同时确保容器本身保持不变。您可能希望通过专门化该类来公开容器的更多功能,例如向量通过提供索引运算符。

我不完全确定公开这样的容器是否是好的设计,但在某些情况下它绝对是一种有用的模式。

【讨论】:

【参考方案4】:

这是正确的方法,除非用户使用const_cast 来消除常量。

【讨论】:

【参考方案5】:

与其返回对向量的引用,不如返回一个包装向量的新类型(包含对向量的 const 引用)并仅公开您希望允许调用者访问的功能。我猜这并不多,因为您想防止向量的可变性。

【讨论】:

【参考方案6】:

一般来说这是不好的做法。您正在向调用者公开您的内部实现。您最好返回包装类实例(前面提到过)或公开获取项目或迭代器的函数(类型定义以匹配您的实现)

【讨论】:

只读向量不公开任何内容。该函数对调用者隐藏底层表示。证据是,如果有必要,基础表示可能会在未来的某个时候发生变化。只要公共接口没有改变,调用者就不会受到改变的影响。这实际上是良好实践的关键属性。只读向量也比编写自定义迭代器好得多,因为 STL 对象具有丰富的接口,包括迭代器、访问操作和容量查询。不要重新发明***。【参考方案7】:

所以基本上,使用“const &”应该向任何 C++ 程序员表明:你真的不应该修改它。如果您真的很偏执,则必须克隆向量。

【讨论】:

以上是关于如何返回向量的“只读”副本的主要内容,如果未能解决你的问题,请参考以下文章

编译器可以省略以下副本吗?

抽象类的 shared_ptr 向量到副本向量

Unity如何理解Vector3.normalized 归一化向量 以及 向量方向计算

我返回时如何避免复制

Linux学习之“fork函数”

C++ - 返回指针或常量引用