16

假设程序员没有故意做一些奇怪的事情,比如专业化,那么进入 areinterpret_cast是否安全(理论上或实际上)?std::pair<T1, T2> const &std::pair<T1 const, T2> const &std::pair<T1 const, T2>

4

3 回答 3

8

这样做是不便携的。

std::pair要求在第 20.3 条中列出。第 17.5.2.3 条阐明

第 18 到 30 条和附录 D 没有指定类的表示,并且有意省略了类成员的说明。实现可以定义静态或非静态类成员,或两者,根据需要实现第 18 到 30 条和附录 D 中指定的成员函数的语义。

这意味着实现包含部分专业化是合法的(尽管极不可能),例如:

template<typename T1, typename T2>
struct pair<T1, T2>
{
    T1 first;
    T2 second;
};

template<typename T1, typename T2>
struct pair<const T1, T2>
{
    T2 second;
    const T1 first;
};

显然与布局不兼容。first其他变体,包括可能在规则之前和/或second在规则下也允许包含其他非静态数据成员。


现在,考虑一下布局已知的情况有点有趣。尽管 Potatoswatter 指出了DR1334断言并且T与布局const T兼容,但该标准提供了足够的保证,让我们无论如何都能获得大部分内容:

template<typename T1, typename T2>
struct mypair<T1, T2>
{
    T1 first;
    T2 second;
};

mypair<int, double> pair1;
mypair<int, double>* p1 = &pair1;
int* p2 = reinterpret_cast<int*>(p1); // legal by 9.2p20
const int* p3 = p2;
mypair<const int, double>* p4 = reinterpret_cast<mypair<const int, double>*>(p3); // again 9.2p20

但是,这不起作用,std::pair因为我们无法应用 9.2p20 而不知道它first实际上是初始成员,但未指定。

于 2013-01-11T19:25:38.803 回答
6

pair在标准的第 20.3.2 节中定义为具有数据成员:

template <class T1, class T2>
struct pair {
    T1 first;
    T2 second;
};

这意味着对于具体类型T1、和T2,保证具有各自的数据成员:pair<T1, T2>pair<const T1, T2>

struct pair<T1, T2> {
    T1 first;
    T2 second;
};
struct pair<const T1, T2> {
    const T1 first;
    T2 second;
};

现在,如果T1T2都是标准布局,那么pair<T1, T2>pair<const T1, T2>都是标准布局。如上所述,在DR1334中,它们与布局不兼容(3.9p11),但在 9.2p19 中,它们可以是reinterpret_cast各自的T1const T1第一个成员。到 9.2p13,T2第二个成员必须位于第一个成员之后(即具有更高的地址),并且到 1.8p5 必须立即位于第一个成员之后,以便在考虑对齐后对象是连续的(9.2p19)。

我们可以使用offsetof(为标准布局类型定义)检查这一点:

static_assert(offsetof(pair<T1, T2>, second) ==
    offsetof(pair<const T1, T2>, second), "!");

由于pair<T1, T2>pair<const T1, T2>具有相同的布局,正向转换并使用结果访问成员在 3.9.2p3 中有效:

如果一个类型的对象T位于一个地址,那么一个值为地址的cvA类型的指针被称为指向该对象,而不管该值是如何获得的。 T*A

所以reinterpret_cast只有std::is_standard_layout<std::pair<T1, T2>>::valueis才是安全的true

于 2013-01-11T19:14:29.073 回答
0

实际的答案是转换为 const 应该是安全的,因为您正在重新解释转换为具有相同表示的对象。但是,反过来会引入未定义的行为(const to non-const)。

至于“理论上的”答案,我应该注意到 C++ 标准不保证 const/non-const 对象的相同按位表示。const 关键字保证“概念上的 constness”,这取决于实现。

于 2013-01-11T17:31:20.873 回答