矢量和const

use*_*508 23 c++ stl const vector

考虑一下

 void f(vector<const T*>& p)
 {
 }
 int main()
 { 
  vector<T*> nonConstVec;
  f(nonConstVec);
 }
Run Code Online (Sandbox Code Playgroud)

下列情况不compile.The事情是vector<T*>不能转换到vector <const T*>,这不合逻辑对我来说,因为存在从隐式转换T*const T*.为什么是这样 ?

vector<const T*>也不能转换为vector <T*>,但这是预期的,因为const T*无法隐式转换为T*.

MSa*_*ers 38

我在你的代码中添加了几行代码.这足以说清楚为什么不允许这样做:

void f(vector<const T*>& p)
 {
    static const T ct;
    p.push_back(&ct); // adds a const T* to nonConstVec !
 }
 int main()
 { 
  vector<T*> nonConstVec;
  f(nonConstVec);
  nonConstVec.back()->nonConstFunction();
 }
Run Code Online (Sandbox Code Playgroud)

  • @marcin:这在理论上是安全的,但如果没有详细了解`std :: vector`,编译器就无法确定.此外,要使其合法化,需要对转换序列规则进行复杂的更改.对于要将`Foo <T*>`转换为`const Foo <const T*>`,`template <class T> class Foo`有什么要求?请记住,在这种情况下,`Foo`可以是智能指针模板或其他任何东西,不一定是容器. (2认同)

Nik*_*nić 22

vector<T>并且vector<const T>是不相关的类型.这个事实T可以被转换为const T在这里并不意味着一件事.

你必须从类型系统的角度考虑它.实例化vector<int>没有任何共同点vector<const int>.


Ste*_*sop 13

可能值得说明为什么执行所需的转换会违反const-correctness:

#include <vector>
const int a = 1;

void addConst(std::vector<const int *> &v) {
    v.push_back(&a); // this is OK, adding a const int* to a vector of same
}

int main() {
    std::vector<int *> w;
    int b = 2;
    w.push_back(&b);  // this is OK, adding an int* to a vector of same
    *(w.back()) = 3;  // this is OK, assigning through an int*
    addConst(w);      // you want this to be OK, but it isn't...
    *(w.back()) = 3;  // ...because it would make this const-unsafe.
}
Run Code Online (Sandbox Code Playgroud)

问题是vector<int*>.push_back需要一个指向非const的指针(从现在开始我称之为"非const指针").这意味着,它可能会修改其参数的指针.特别是在vector的情况下,它可能会将指针移回给修改它的其他人.所以你不能将const指针传递给w的push_back函数,即使模板系统支持它,你想要的转换也是不安全的(它没有).const-safety的目的是阻止你将const指针传递给一个带有非const指针的函数,这就是它的工作方式.C++要求您具体说明是否要做一些不安全的事情,因此转换肯定不能隐含.事实上,由于模板的工作方式,根本不可能(见后文).

我认为C++原则上可以通过允许从一个转换保持常量安全vector<T*>&const vector<const T*>&,就像int **const int *const *是安全的.但这是因为定义了矢量的方式:对于其他模板来说,它不一定是安全的.

同样,它理论上可以允许显式转换.事实上,它确实允许显式转换,但仅适用于对象,而不是引用;-)

std::vector<const int*> x(w.begin(), w.end()); // conversion
Run Code Online (Sandbox Code Playgroud)

它不能用于引用的原因是因为模板系统不能支持它.如果允许转换,将会破坏的另一个示例:

template<typename T> 
struct Foo {
    void Bar(T &);
};

template<>
struct Foo<const int *> {
    void Baz(int *);
};
Run Code Online (Sandbox Code Playgroud)

现在,Foo<int*>没有Baz功能.如何将指针或引用Foo<int*>转换为指针或引用Foo<const int*>

Foo<int *> f;
Foo<const int *> &g = f; // Not allowed, but suppose it was
int a;
g.Baz(&a); // Um. What happens? Calls Baz on the object f?
Run Code Online (Sandbox Code Playgroud)


Mar*_*ork 6

想象这样:

你有两个这样的课:

class V  { T*       t;};
class VC { T const* t;};
Run Code Online (Sandbox Code Playgroud)

你期望这两个类可以自动转换吗?
这基本上就是模板类.每种变体都是一种全新的变体.

因此,vector <T*>和vector <T const*>是完全不同的类型.

我的第一个问题是你真的想存储指针吗?

如果是的话,我建议看一下boost :: ptr_container.它保存指针并在向量被销毁时删除它们.但更重要的是,它将包含的指针视为普通的std:vector处理其包含的对象.因此,通过制作向量const,您只能以const形式访问其成员

void function(boost::ptr_vector<T> const& x)
{
     x.push_back(new T);  // Fail x is const.
     x[4].plop();         // Will only work if plop() is a const member method.
}
Run Code Online (Sandbox Code Playgroud)

如果您不需要存储指针,则将对象(而不是指针)存储在容器中.

void function(std::vector<T> const& x)
{
     x.push_back(T());    // Fail x is const.
     x[4].plop();         // Will only work if plop() is a const member method.
}
Run Code Online (Sandbox Code Playgroud)