向量和常量
考虑一下
void f(vector<const T*>& p)
{
}
int main()
{
vector<T*> nonConstVec;
f(nonConstVec);
}
以下内容无法编译。问题是 vector
无法转换为 vector
,这似乎不合逻辑对我来说,因为存在从 T*
到 const T*
的隐式转换。这是为什么?
vector
也无法转换为 vector
,但这是预期的,因为 const T*
无法隐式转换为 T*
。
Consider this
void f(vector<const T*>& p)
{
}
int main()
{
vector<T*> nonConstVec;
f(nonConstVec);
}
The following does not compile.The thing is that vector<T*>
can not be converted to vector <const T*>
, and that seems illogically to me , because there exists implicit conversion from T*
to const T*
. Why is this ?
vector<const T*>
can not be converted to vector <T*>
too, but that is expected because const T*
can not be converted implicitly to T*
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我已在您的代码中添加了几行。这足以清楚为什么这是不允许的:
I've added a few lines to your code. That's sufficient to make it clear why this is disallowed:
vector
和vector
是不相关的类型。T
可以转换为const T
的事实在这里没有任何意义。您必须从类型系统的角度来考虑它。实例化的
vector
与vector
没有任何共同点。vector<T>
andvector<const T>
are unrelated types. The fact thatT
can be converted toconst T
doesn't mean a thing here.You have to think about it from a type system's standpoint. Instantiated
vector<int>
doesn't have anything in common withvector<const int>
.可能值得说明为什么执行您想要的转换违反了 const 正确性:
问题是
vector.push_back
采用指向非 const 的指针(其中从现在开始我将称之为“非常量指针”)。这意味着,它可能会修改其参数的指针。特别是在向量的情况下,它可能会将指针交还给修改它的其他人。因此,您不能将 const 指针传递给 w 的 push_back 函数,并且即使模板系统支持它(但它不支持),您想要的转换也是不安全的。 const 安全的目的是阻止您将 const 指针传递给采用非 const 指针的函数,这就是它的工作方式。 C++ 要求你明确说明是否想做一些不安全的事情,因此转换当然不能是隐式的。事实上,由于模板的工作方式,这是根本不可能的(见下文)。我认为 C++ 原则上可以通过允许从
vector&
到const vector&
的转换来保留 const 安全性,只是因为int **
到const int *const *
是安全的。但这是因为向量的定义方式:对于其他模板来说它不一定是常量安全的。同样,理论上它可以允许显式转换。事实上,它确实允许显式转换,但仅限于对象,而不是引用;-)
它不能对引用执行此操作的原因是模板系统不支持它。如果允许转换,则会损坏另一个示例:
现在,
Foo
没有 Baz 函数。到底如何将Foo
的指针或引用转换为Foo
的指针或引用?It may be worth showing why it's a breach of const-correctness to perform the conversion you want:
The problem is that
vector<int*>.push_back
takes a pointer-to-non-const (which I'll call a "non-const pointer" from now on). That means, it might modify the pointee of its parameter. Specifically in the case of vector, it might hand the pointer back out to someone else who modifies it. So you can't pass a const pointer to the push_back function of w, and the conversion you want is unsafe even if the template system supported it (which it doesn't). The purpose of const-safety is to stop you passing a const pointer to a function which takes a non-const pointer, and this is how it does its job. C++ requires you to specifically say if you want to do something unsafe, so the conversion certainly can't be implicit. In fact, because of how templates work, it's not possible at all (see later).I think C++ could in principle preserve const-safety by allowing a conversion from
vector<T*>&
toconst vector<const T*>&
, just asint **
toconst int *const *
is safe. But that's because of the way vector is defined: it wouldn't necessarily be const-safe for other templates.Likewise, it could in theory allow an explicit conversion. And in fact, it does allow an explicit conversion, but only for objects, not references ;-)
The reason it can't do it for references is because the template system can't support it. Another example that would be broken if the conversion were allowed:
Now,
Foo<int*>
doesn't have a Baz function. How on earth could a pointer or reference toFoo<int*>
be converted to a pointer or reference toFoo<const int*>
?像这样思考:
您有两个这样的类:
您希望这两个类能够自动转换吗?
这基本上就是模板类。每个变体都是全新的类型。
因此向量 T* 是和向量是完全不同的类型。
我的第一个问题是你真的想存储指针吗?
如果是,我建议查看 boost::ptr_container。它保存指针并在向量被销毁时删除它们。但更重要的是,它对待包含的指针就像普通的 std:vector 对待其包含的对象一样。因此,通过将向量设置为 const,您只能将其成员作为 const 访问。
如果不需要存储指针,则将对象(而不是指针)存储在容器中。
Think of like this:
You have two class like this:
Do you expect these two classes to be convertible automatically?
This is basically what a template class is. Each variation is a completely new type.
Thus vector<T*> and vector<T const*> are completely different types.
My first question is do you really want to store pointers?
If yes, I would suggest looking at boost::ptr_container. This holds pointers and deletes them when the vector is destroyed. But more importantly it treats the contained pointers as a normal std:vector treats its contained objects. Thus by making the vector const you can only access its members as const
If you don't need to store pointers then store the objects (not the pointers) in the container.
其他人已经给出了您给出的代码无法编译的原因,但我对如何处理它有不同的答案。我不相信有任何方法可以教编译器如何自动转换两者(因为这将涉及更改 std::vector 的定义)。解决这个烦恼的唯一方法是进行显式转换。
转换为完全不同的向量是不令人满意的(浪费内存和周期来处理应该完全相同的东西)。我建议如下:
我使用
reinterpret_cast
来声明这两件事是相同的。使用后你应该感觉很脏,但如果你把它单独放在一个函数中,并为关注你的人发表评论,那么就洗漱一下,然后问心无愧地继续你的路吧。你总是(正确地)会担心有人把你脚下的地面拔掉。Others have already given the reason why the code you gave doesn't compile, but I have a different answer on how to deal with it. I don't believe there's any way to teach the compiler how to automatically convert the two (because that would involve changing the definition of
std::vector
). The only way around this annoyance is to do an explicit conversion.Converting to a completely different vector is unsatisfying (wastes memory and cycles for something that should be completely identical). I suggest the following:
I'm using
reinterpret_cast
to declare that the two things are the same. You SHOULD feel dirty after using it, but if you put it in a function by itself with a comment for those following you, then have a wash and try to continue on your way with a good conscience, though you will always (rightly) have that nagging worry about someone pulling the ground out from under you.正如其他人所说,转换不适用于模板参数。换句话说,
...和:
...是完全不同的类型。
如果您尝试实现关于 f() 的常量正确性而不修改向量的内容,这可能更符合您正在寻找的内容:
As others have said, conversions aren't applied to the template parameters. Put another way,
...and:
... are completely different types.
If you are trying to implement const-correctness in regard to f() not modifying the contents of the vector, this might be more along the lines of what you're looking for:
除了其他答案之外,值得阅读 C++ FQA Lite,其中从关键 POV 讨论了此功能(以及许多其他 C++ 功能):
http://yosefk.com/c++fqa/const.html#fqa -18.1
in addition to other answers, it's worth reading C++ FQA Lite where this (and many others C++ features) are discussed from a critical POV:
http://yosefk.com/c++fqa/const.html#fqa-18.1
这就是模板的工作方式 - 不对模板参数应用转换,因此两个向量具有完全不同的类型。
That's the way templates work - no conversions are applied on the template parameters, so the two vectors are of completely different types.
vector
和vector
是完全不同的类型。即使您在main()
中编写const T*
,您的代码也无法编译。您需要在 main 内部提供专业化。编译如下:
Both
vector<const T*>
andvector<T*>
are completely different types. Even if you writeconst T*
inside yourmain()
, your code wont compile. You need to provide specialization inside main.The following compiles:
模板在这方面有点奇怪。存在从 T 到 U 的隐式转换这一事实并不意味着存在从 XXX 到 XXX 的隐式转换。它可以实现,但需要在模板代码中进行大量额外的工作才能实现它,而且我怀疑在设计
std::vector
时这些技术是否都已为人所知(更准确地说,我很确定他们不为人所知)。编辑:像这样的问题是使用迭代器背后的动机的一部分。即使
X 容器
不能隐式转换为const X 容器
,container::iterator
可以隐式转换为container::const_iterator
。如果你
用
: 替换你的:那么:
就可以了 - 所以也会:
Templates are a bit strange that way. The fact that there's an implicit conversion from T to U doesn't mean that there's an implicit conversion from XXX to XXX. It can be made to happen, but it takes a fair amount of extra work in the template code to make it happen, and offhand, I doubt the techniques were all known when
std::vector
was being designed (more accurately, I'm pretty sure they weren't known).Edit: Issues like this are part of the motivation behind using iterators. Even though a
container of X
isn't implicitly convertible to acontainer of const X
, acontainer<X>::iterator
is implicitly convertible to acontainer<X>::const_iterator
.If you replace your:
with:
Then:
will be just fine -- and so will: