[英]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的正確解釋。
當然,我可以輕松地創建一個適當的函數,但它比單行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);
}
像這樣的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));
一般的模板和容器(我將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
類型的對象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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.