C + + 11允许向量 < const T > 吗?

容器需求已经从 C + + 03改为 C + + 11。虽然 C + + 03有一揽子要求(例如,向量的可复制构造性和可分配性) ,但 C + + 11定义了每个集装箱操作的细粒度要求(第23.2节)。

因此,你可以在一个向量中存储一个可复制构造但不可赋值的类型,比如一个带有 const 成员的结构,只要你只执行某些不需要赋值的操作(构造和 push_back就是这样的操作,而 insert不是)。

我想知道的是: 这是否意味着标准现在允许 vector<const T>?我看不出有什么理由不这样做—— const T,就像一个包含 const 成员的结构,是一种可复制构造但不可赋值的类型——但我可能遗漏了什么。

(让我觉得我可能遗漏了一些东西的部分原因是,如果您尝试实例化 vector<const T>,gcc 主干会崩溃并烧毁,但是对于 T 有一个 const 成员的 vector<T>来说,这没有问题)。

18518 次浏览

No, I believe the allocator requirements say that T can be a "non-const, non-reference object type".

You wouldn't be able to do much with a vector of constant objects. And a const vector<T> would be almost the same anyway.


Many years later this quick-and-dirty answer still seems to be attracting comments and votes. Not always up. :-)

So to add some proper references:

For the C++03 standard, which I have on paper, Table 31 in section [lib.allocator.requirements] says:

T, U any type

Not that any type actually worked.

So, the next standard, C++11, says in a close draft in [allocator.requirements] and now Table 27:

T, U, C any non-const, non-reference object type

which is extremely close to what I originally wrote above from memory. This is also what the question was about.

However, in C++14 (draft N4296) Table 27 now says:

T, U, C any non-const object type

Possibly because a reference perhaps isn't an object type after all?

And now in C++17 (draft N4659) it is Table 30 that says:

T, U, C any cv-unqualified object type (6.9)

So not only is const ruled out, but also volatile. Probably old news anyway, and just a clarification.


Please also see Howard Hinnant's first-hand info, currently right below.

Update

Under the accepted (and correct) answer I commented in 2011:

Bottom line: We didn't design containers to hold const T. Though I did give it some thought. And we came really close to doing it by accident. To the best of my knowledge, the current sticking point is the pair of overloaded address member functions in the default allocator: When T is const, these two overloads have the same signature. An easy way to correct this would be to specialize std::allocator<const T> and remove one of the overloads.

With the upcoming C++17 draft it appears to me that we have now legalized vector<const T>, and I also believe we've done it accidentally. :-)

P0174R0 removes the address overloads from std::allocator<T>. P0174R0 makes no mention of supporting std::allocator<const T> as part of its rationale.

Correction

In the comments below T.C. correctly notes that the address overloads are deprecated, not removed. My bad. The deprecated members don't show up in in 20.10.9 where the std::allocator is defined, but are instead relegated to section D.9. I neglected to scan Chapter D for this possibility when I posted this.

Thank you T.C. for the correction. I contemplated deleting this misleading answer, but perhaps it is best to leave it up with this correction so that perhaps it will keep someone else from misreading the spec in the same way I did.

Even though we already have very good answers on this, I decided to contribute with a more practical answer to show what can and what cannot be done.

So this doesn't work:

vector<const T> vec;

Just read the other answers to understand why. And, as you may have guessed, this won't work either:

vector<const shared_ptr<T>> vec;

T is no longer const, but vector is holding shared_ptrs, not Ts.

On the other hand, this does work:

vector<const T *> vec;
vector<T const *> vec;  // the same as above

But in this case, const is the object being pointed to, not the pointer itself (which is what the vector stores). This would be equivalent to:

vector<shared_ptr<const T>> vec;

Which is fine.

But if we put const at the end of the expression, it now turns the pointer into a const, so the following won't compile:

vector<T * const> vec;

A bit confusing, I agree, but you get used to it.

Complementing the other answers, another approach is to use:

vector<unique_ptr<const T>> vec;

If it is the case where you want to enforce that only vec has ownership of its items. Or if you want a dynamic of moving items into vec and at some point move them out.

As pointed out, pointer const semantics may be confusing, but shared_ptr and unique_ptr aren't. const unique_ptr<T> is a const pointer and unique_ptr<const T> is a const pointee as you would expect.

To my best knowledge, if you want each T element in your vector is const, just use const vector instead. Because if your vector is const-qualified, only the const-qualified methods that won't modify any T element can be called.