以下代码不能在C ++ 11(也不是C ++ 14)中编译。我理解编译器输出的错误,但为什么标准不允许这样做?
//main.cpp
#include <vector>
int main(void)
{
double a = 3.0;
double b = 3.0;
//It works with mere pointers
const double* ptrToConst = &a;
/***/ double* ptrToObj = &a;
// ptrToObj = ptrToConst; //Illegal : that's understandable…
ptrToConst = ptrToObj; //Works
//But the same doesn't work with vectors to pointers
std::vector<const double*> ptrsToConst = {&a, &b};
std::vector</***/ double*> ptrsToObj = {&a, &b};
// ptrsToObj = ptrsToConst; //Illegal : that's understandable
ptrsToConst = ptrsToObj; //Illegal : but why?!
}
错误来自第ptrsToConst = ptrsToObj
行。实际上,似乎不可能将指针std::vector<T*>
的向量复制到指向常量std::vector<const T*>
的指针向量中。请注意,在这两种情况下,指针本身都是不常量。
为什么这项行动是非法的? 什么是最优雅的工作?
如果我通过调用clang++ --std=c++11 main.cpp
进行编译,则会显示以下错误消息:
main.cpp:19:17: error: no viable overloaded '='
ptrsToConst = ptrsToObj; //Illegal : but why?!
~~~~~~~~~~~ ^ ~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:436:7: note: candidate
function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'const
vector<const double *, allocator<const double *>>' for 1st argument
operator=(const vector& __x);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:448:7: note: candidate
function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'vector<const
double *, allocator<const double *>>' for 1st argument
operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:470:7: note: candidate
function not viable: no known conversion from 'std::vector<double *>' to 'initializer_list<value_type>' (aka
'initializer_list<const double *>') for 1st argument
operator=(initializer_list<value_type> __l)
^
1 error generated.
尝试使用gcc(g ++)会产生类似的错误消息。
显然,实现vector的方式不允许我尝试执行的操作。然而,这是关于const正确性的安全操作,对吧?
答案 0 :(得分:11)
您可以执行此操作,而不是使用operator=
。您需要assign
成员函数,该函数对每个元素执行转换。
ptrsToConst.assign(ptrsToObj.begin(), ptrsToObj.end());
答案 1 :(得分:4)
因为它是std::vector
的实现方式:分配运算符要求另一个操作数具有相同的类型。 vector<double *>
和vector<const double *>
的类型不同,因为即使兼容类型,double
和const double
也不同。
可以想象只将这个要求放宽到兼容的类型,但实现起来会更复杂,当标准容器的实现已经足够复杂时(只需读取一次矢量标题......),而且两者的编写者都没有。图书馆和标准委员会认为有必要。
如果你真的需要它,你将不得不编写一个自定义实现...
答案 2 :(得分:-2)
我不确定,但也许c ++通过引用将std::vector<T*>
对象复制到std::vector<const T*>
对象。这意味着c ++不会为std::vector<const T*>
的新构造对象分配新内存。这个std::vector<const T*>
的新构造对象将是std::vector<T*>
的旧对象的另一个名称(或引用)。然后,有意义的是为什么会出现错误。因为std::vector<T*>
的对象可以改变它所指向的对象,但是std::vector<const T*>
的对象不能改变它所指向的对象。