reinterpret_cast 指向基类指针向量的指针向量

Raf*_*fal 5 c++ class-hierarchy reinterpret-cast

考虑下面的一段代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是使用reinterpret_castto cast from std::vector<std::shared_ptr<Derived>>tostd::vector<std::shared_ptr<const Base>>&是否可行并被标准接受。

我已经用 clang-3.8 和 gcc-6.1 编译了代码,-fsanitize=undefined看起来没问题。但是,我似乎无法找到有关 cppreference 的正确解释。

当然,我可以轻松创建一个适当的函数,但它比一行 reinterpret_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);
}
Run Code Online (Sandbox Code Playgroud)

Leo*_*eon 2

reinterpret_cast像这样是未定义的行为。Derived*当从to转换需要指针调整时,代码将中断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]
Run Code Online (Sandbox Code Playgroud)

如果您的目标只是使其以最简洁的方式工作,而不是避免通过临时向量进行转换,那么在这种特殊情况下,您可以使用此答案container_cast中提出的实用程序。

update(container_cast(elements));
Run Code Online (Sandbox Code Playgroud)