我可以在向量中使用const来允许添加元素,但不能修改已经添加的元素吗?

我对这个答案的评论让我想到了常量和sorting的问题。 我玩了一下,减less了我的问题,这个代码:

#include <vector> int main() { std::vector <const int> v; } 

不会编译 – 你不能创build一个const int的向量。 显然,我应该知道这一点(在智力上我也是),但是我从来没有必要去创造这样的事情。 然而,对我来说,这似乎是一个有用的构造,我想知道是否有任何方法绕过这个问题 – 我想添加东西到一个vector(或其他),但不应该改变一旦添加。

可能有一些令人难堪的简单解决scheme,但这是我以前从未考虑过的事情。 我可能不应该提到sorting(我可能会问另一个问题,请参阅这个问题的困难)。 我真正的基本用例是这样的:

 vector <const int> v; // ok (ie I want it to be OK) v.push_back( 42 ); // ok int n = v[0]; // ok v[0] = 1; // not allowed 

那么,在C ++ 0x你可以…

在C ++ 03中,有一个段落23.1 [lib.containers.requirements] / 3,它说

存储在这些组件中的对象的types必须满足CopyConstructibletypes(20.1.3)的要求,以及Assignabletypes的附加要求。

这是目前阻止你使用const int作为std::vectortypes的参数。

但是,在C ++ 0x中,这个段落丢失了,相反, T需要是可Destructible ,并且对每个expression式指定了对T附加要求,例如std::vector上的v = u只有在TMoveConstructibleMoveAssignable

如果我正确地解释了这些要求,应该可以实例化std::vector<const int> ,你只是会缺less它的一些function(我猜是你想要的)。 您可以通过将一对迭代器传递给构造函数来填充它。 我认为emplace_back()应该能够工作,尽pipe我没有在T上find明确的要求。

尽pipe如此,您仍然无法对vector进行sorting。

您放入标准容器的types必须是可复制和可分配的。 auto_ptr造成这么多麻烦的原因正是因为它不遵循正常的复制和分配语义。 自然,任何const都不会被赋值。 所以,你不能在一个标准容器中粘贴任何东西。 如果元素不是const ,那么你将能够改变它。

我认为最接近的解决scheme是使用某种间接方法。 所以,你可以有一个指向const的指针,或者你可以拥有一个保存你想要的值的对象,但是这个值不能在对象中改变(就像你用Java中的Integer得到的那样)。

具有特定索引的元素是不可改变的,这与标准容器的工作方式有关。 你可能能够构build自己的工作方式,但标准的不这样做。 没有一个基于数组的都可以工作,除非你可以设法将它们的初始化符合到{a, b, c}初始化语法中,因为一旦创build了一个const数组,就不能改变它。 所以,无论你做什么, vector类都不可能和const元素一起工作。

在没有某种间接性的情况下在一个容器中存在const就不能很好地工作。 你基本上要求整个容器是const – 如果你从一个已经初始化的容器复制它,你可以做到这一点,但是你真的不能有一个容器 – 当然不是一个标准的容器 – 它包含的常量没有某种间接。

编辑 :如果你要做的是大多留下一个容器不变,但仍然能够在代码中的某些地方改变它,然后在大多数地方使用const ref,然后给代码,需要能够改变容器的直接访问权限,或者一个非const的引用会使这个成为可能。

因此,在大多数地方使用const vector<int>& ,然后使用vector<int>&需要更改容器的位置,或者让代码的这部分直接访问容器。 这样,它几乎是不变的,但你可以改变它,当你想。

另一方面,如果你想几乎总是能够改变容器中的内容,但不改变特定的元素,那么我build议在容器周围放置一个包装类。 在vector的情况下,包装它,使下标操作符返回一个常量参考,而不是一个非常量参考 – 无论是一个副本。 所以,假设你创build了一个模板化版本,你的下标操作符看起来像这样:

 const T& operator[](size_t i) const { return _container[i]; } 

这样,您可以更新容器本身,但不能更改它的个别元素。 只要你声明所有的内联函数,它不应该是一个性能打击(如果有的话)的包装。

你不能创build一个const int的向量,即使你可以,它也是无用的。 如果我删除了第二个int,那么从那里开始的所有内容都会向下移动一个 – 读取:modified – 使得不可能保证v [5]在两个不同的场合具有相同的值。

除此之外,一个const声明后就不能赋值,只能抛出const。 如果你想这样做,为什么你首先使用const?

你将需要写你自己的class级。 你当然可以使用std :: vector作为你的内部实现。 然后只需要实现const接口和那些你需要的那些非const函数。

虽然这不能满足您的所有要求(可以sorting),但请尝试一个常量向量:

 int values[] = {1, 3, 5, 2, 4, 6}; const std::vector<int> IDs(values, values + sizeof(values)); 

虽然,你可能想要使用std::list 。 在列表中,值不需要改变,只有链接到他们。 sorting是通过改变链接的顺序来完成的。

你可能不得不花费一些脑力来写自己的东西。 🙁

我将所有的const对象在一个标准的数组。
然后在数组中使用指针向量。
一个小实用程序类只是为了帮助您不必去参考对象和干草。

 #include <vector> #include <algorithm> #include <iterator> #include <iostream> class XPointer { public: XPointer(int const& data) : m_data(&data) {} operator int const&() const { return *m_data; } private: int const* m_data; }; int const data[] = { 15, 17, 22, 100, 3, 4}; std::vector<XPointer> sorted(data,data+6); int main() { std::sort(sorted.begin(), sorted.end()); std::copy(sorted.begin(), sorted.end(), std::ostream_iterator<int>(std::cout, ", ")); int x = sorted[1]; } 

我与诺亚:用一个只公开你想要允许的类包装向量。

如果你不需要dynamic添加对象的vector,考虑std::tr1::array

如果在这个例子中const是非常重要的,我想你可能希望一直使用不可变types。 从概念上讲,你将有一个固定的大小,常量int的const数组。 任何时候你需要改变它(例如,添加或删除元素,或sorting),你需要做一个数组的副本与执行的操作,并使用它。 虽然这在函数式语言中是非常自然的,但在C ++中看起来不太“正确”。 例如,获得高效的sorting实现可能会非常棘手 – 但是您不会说性能要求是什么。 无论你认为这条路线是否从性能/定制代码的angular度来看是值得的,我相信这是正确的做法。

之后,通过非常量指针/智能指针保存值可能是最好的(但有其自己的开销,当然)。

我一直在想这个问题,似乎你的要求是closures的。

你不想为你的向量添加不可变的值:

 std::vector<const int> vec = /**/; std::vector<const int>::const_iterator first = vec.begin(); std::sort(vec.begin(), vec.end()); assert(*vec.begin() == *first); // false, even though `const int` 

你真正想要的是你的向量保持一个不变的值集合,以一个可修改的顺序,即使它工作,也不能用std::vector<const int>语法表示。

恐怕这是一个非常具体的任务,需要一个专门的课程。

的确, Assignable是向量元素types的标准要求之一,并且const int是不可赋值的。 但是,我期望在一个经过深思熟虑的实现中,编译只有在代码明确依赖于赋值时才会失败。 例如,对于将inserterase std::vector

实际上,在许多实现中,即使不使用这些方法,编译也会失败。 例如,Comeau无法编译普通的std::vector<const int> a; 因为相应的std::allocator不能编译。 它报告std::vector本身没有直接的问题。

我相信这是一个有效的问题。 如果types参数是const限定的,库提供的实现std::allocator应该失败。 (我想知道是否有可能做一个std::allocator的自定义实现来强制整个东西编译。)(这也将是有趣的知道VS如何pipe理编译它)同样,与Comeau std::vector<const int>编译器出于同样的原因失败std::allocator<const int>编译失败,根据std::allocator的规范,编译失败。

当然,在任何情况下,任何实现都有权无法编译std::vector<const int>因为语言规范允许它失败。

只使用一个未专门的vector ,这是不能做到的。 sorting是通过使用赋值完成的。 所以相同的代码,使这成为可能:

sort(v.begin(), v.end());

…也使这成为可能:

v[1] = 123;

你可以从std :: vector派生一个类const_vector,它重载了任何返回一个引用的方法,并且返回一个const引用。 要做你的sorting,请回到std :: vector。

常量对象的std::vector可能会由于Assignable要求而无法编译,因为不能Assignable常量对象。 移动分配也是如此。 当使用基于vector的地图(如boost flat_map或Loki AssocVector时,这也是我经常遇到的问题。 因为它有内部实现std::vector<std::pair<const Key,Value> > 。 因此,根据地图的const key要求几乎是不可能的,这对于任何基于节点的地图来说都很容易实现。

然而,可以看出, std::vector<const T>是指向量应该存储一个const Ttypes的对象,或者它只需要在访问时返回一个不可变的接口。 在这种情况下,遵循Assignable / Move Assignable要求的std::vector<const T>是可能的,因为它存储Ttypes的对象而不是const T 标准的typedef和allocatortypes需要修改一点,以支持标准requirements.Though支持这样的flat_mapflat_map ,可能需要在std::pair接口相当大的变化,因为它直接暴露成员variables第一和第二。

编译失败,因为push_back() (例如)基本上是

 underlying_array[size()] = passed_value; 

两个操作数都是T& 。 如果T是无法工作的const X

const的元素在原理上看起来是正确的,但在实践中它是不自然的,规范并没有说它应该被支持,所以它不存在。 至less不在stdlib中(因为那样它就会在vector中)。