为什么std::vector将其constness传递给所包含的对象

Why does std::vector transfer its constness to the contained objects?

本文关键字:包含 对象 std vector 将其 constness 为什么      更新时间:2023-10-16

A const int *和A int *const是非常不同的。同理,const std::auto_ptr<int> vs. std::auto_ptr<const int>。然而,const std::vector<int>std::vector<const int>之间似乎没有这样的区别(实际上我不确定第二种是否被允许)。为什么会这样?

有时我有一个函数,我想传递一个对向量的引用。函数不应该修改向量本身(例如:没有push_back()),但它想修改每个包含的值(例如,增加它们)。类似地,我可能希望一个函数只改变向量结构,而不修改它的任何现有内容(尽管这可能是奇怪的)。这种事情对于std::auto_ptr(例如)是可能的,但是因为std::vector::front()(例如)被定义为

const T &front() const;
T &front();

而不仅仅是

T &front() const;

这是无法表达的

我想做的例子:

//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();

//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();

这是一个设计决策。

如果你有一个const容器,你通常不希望任何人修改它所包含的元素,这是它的内在组成部分。容器完全"拥有"这些元素,可以说是"巩固了这种纽带"。

这与历史上更低级的"容器"实现(即原始数组)形成对比,后者更不受约束。正如你所说的,int const*int * const之间有很大的区别。但是标准容器只是选择传递const属性。

不同之处在于指向int的指针不拥有其所指向的整型,而vector<int>拥有其所包含的整型。可以将vector<int>定义为具有int成员的结构体,其中成员的数量恰好是可变的。

如果你想创建一个可以修改vector中包含的值但不能修改vector本身的函数,那么你应该设计这个函数来接受迭代器参数。

的例子:

void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
    std::for_each(begin, end, [](int& elem) { elem = 1; });
}

如果你能负担得起把想要的功能放在头文件中,那么它可以通用为:

template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
    typedef typename iterator_traits<OutputIterator>::reference ref;
    std::for_each(begin, end, [](ref elem) { elem = 1; });
}

您建议的一个大问题是:std::vector<const T>std::vector<T>不是同一类型。因此,如果不进行某种转换,就不能将vector<T>传递给需要vector<const T>的函数。不是简单的cast,而是创建一个新的vector<const T>。这个新系统不能简单地与旧系统共享数据;它必须复制或移动数据从旧的到新的。

您可以在std::shared_ptr中解决这个问题,但这是因为它们是共享的指针。可以有两个对象引用同一个指针,因此从std::shared_ptr<T>shared_ptr<const T>的转换不会造成损害(除了增加引用计数)。没有所谓的shared_vector .

std::unique_ptr也可以,因为它们只能移动,不能复制。因此,它们中只有一个会有指针。

所以你所要求的是根本不可能的

  • 你是对的,不可能有const int类型的vector,主要是因为这些元素不能赋值(对vector中包含的元素类型的要求)。
  • 如果你想要一个函数只修改vector的元素,而不向vector本身添加元素,这主要是STL为你做的——拥有不知道元素序列包含在哪个容器中的函数。该函数只是接受一对迭代器,并对该序列执行操作,完全忽略了它们包含在vector中的事实。
  • 查找"插入迭代器"来了解如何在不知道元素是什么的情况下向容器插入内容。例如,back_inserter接受一个容器,它所关心的只是知道该容器有一个名为push_back的成员函数。