interpret_cast指针的向量到基类的指针的向量
reinterpret_cast vector of pointers to vector of pointers to base class
考虑以下代码
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
struct Base {
int x;
Base(int x) : x(x) {}
};
struct Derived : public Base {
int y, z;
Derived(int x) : Base(x), y(x + 1), z(x + 2) {}
};
void update(const std::vector<std::shared_ptr<const Base>>& elements) {
for (const auto elem : elements) {
std::cout << elem->x << "n";
}
}
int main(int, char**) {
std::vector<std::shared_ptr<Derived>> elements(4);
{
int ctr = 0;
std::generate(begin(elements), end(elements), [&ctr]() { return std::make_shared<Derived>(++ctr); });
}
// update(elements); // note: candidate function not viable: no known conversion from 'vector<shared_ptr<Derived>>' to 'const vector<shared_ptr<const Base>>' for 1st argument
update(reinterpret_cast<std::vector<std::shared_ptr<const Base>>&>(elements)); // ok
return 0;
}
我的问题是,使用reinterpret_cast
从std::vector<std::shared_ptr<Derived>>
转换为std::vector<std::shared_ptr<const Base>>&
是否可行并被标准所接受。
我已经用clang-3.8和gcc-6.1用-fsanitize=undefined
编译了代码,看起来还可以。但是,我似乎找不到关于cppreference的正确解释。
当然,我可以很容易地创建一个appropriate函数,但它比一行interpret_cast长,并且需要一个临时向量。
void update(const std::vector<std::shared_ptr<Derived>>& elements) {
std::vector<std::shared_ptr<const Base>> casted(elements.size());
std::copy(begin(elements), end(elements), begin(casted));
update(casted);
}
模板和容器(我将shared_ptr
视为容器的一种特殊形式)在C++中不是协变的。这意味着,如果有两种类型Base
和Derived < Base
以及一种template<typename T> class X {};
,那么X<Base>
和X<Derived>
是两种完全不同的东西,并且没有任何形式的关系。
在您的例子中,您有一个类型为std::vector<std::shared_ptr<Derived>>
的对象,然后创建一个std::vector<std::shared_ptr<const Base>>&
来访问它。我认为这有两个问题:
- 您将类型为
vector
的对象强制转换为引用类型。我真的很想知道为什么这样有效 - 您可以通过不相关的不同类型的引用来访问对象。我认为这违反了严格的别名规则,因此是未定义的行为
如果你用gcc -fstrict-aliasing
编译代码,编译器会认为你的程序符合规则并对其进行优化。它会生成一个警告:
> Start prog.cc: In function 'int main(int, char**)': prog.cc:33:80:
> warning: dereferencing type-punned pointer will break strict-aliasing
> rules [-Wstrict-aliasing]
> update(reinterpret_cast<std::vector<std::shared_ptr<const Base>>&>(elements)); // ok
reinterpret_cast
是未定义的行为。当从Derived*
转换为Base*
需要调整指针时,代码将中断。当Derived
使用多重继承并且Base
不是它的第一个基类时,这种情况很可能发生。
struct Derived : public X, public Base { ... };
Derived* d = new Derived;
Base* b = d; // this is no longer a "no-op", since the Base sub-object
// of Derived is not at offset 0:
//
// d b
// | |
// v v
// [Derived]
// [X][Base]
如果您的目标只是使其以最简洁的方式工作,而不是避免通过临时向量进行转换,那么在这种特殊情况下,您可以使用本答案中提出的container_cast
实用程序。
update(container_cast(elements));
相关文章:
- 函数向量_指针有不同的原型,我可以构建一个吗
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 使用向量类的c++指针
- 如何使用C++初始化向量;脚本化值不是数组、指针或矢量错误
- 如何更改唯一指针向量的可见性
- C++ 独特指针练习的向量
- C 中的向量指针的清晰图
- 当向量位于内部类中时,如何删除指向对象的向量指针
- std::向量指针
- 指向结构体的向量指针错误
- 删除指向指针的向量指针时出错
- 映射不同类型的向量指针
- 在c++中传递向量指针
- 虚拟类的向量:指针是干净的方法吗
- 如何从另一个向量/对象集构造新的向量/指针集
- 模型视图控制器- c++向量指针,太多的传递
- 为什么向量指针占用这么多内存?
- 删除条目向量指针的静态映射c++
- 复向量指针
- c++数组向量指针的初始化