是铸造std :: pair <t1,t2 =“”> const&amp; to std :: pair <t1 const,=“”t2 =“”> const&amp;安全</T1> </T1,>

时间:2013-01-11 05:17:46

标签: c++ templates casting const reinterpret-cast

reinterpret_cast std::pair<T1, T2> const & std::pair<T1 const, T2> const &std::pair<T1 const, T2>是否安全(在理论上或实践中),假设程序员没有故意做一些奇怪的事情,比如专门化{{1}} }?

3 个答案:

答案 0 :(得分:6)

这样做不便携。

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声称Tconst 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,因为我们无法在不知道first实际上是初始成员(未指定)的情况下应用9.2p20。

答案 1 :(得分:4)

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

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

这意味着对于具体类型T1T2pair<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到它们各自的T1或{ {1}}第一个成员。到9.2p13时,const T1第二个成员必须位于第一个成员之后(即地址较高),并且1.8p5必须位于第一个成员之后,以便在考虑对齐后该对象是连续的(9.2p19)

我们可以使用T2(为标准布局类型定义)来检查:

offsetof

由于static_assert(offsetof(pair<T1, T2>, second) == offsetof(pair<const T1, T2>, second), "!"); pair<T1, T2>具有相同的布局,因此向前投射并使用结果访问成员的有效期为3.9.2p3:

  

如果pair<const T1, T2>类型的对象位于地址T,则指向 cv A的指针,其值为地址{{1}无论如何获得该值,都可以指向该对象。

因此T*仅在Areinterpret_cast时才有效。

答案 2 :(得分:0)

实际的答案是,由于您要重新解释为具有相同表示的对象,因此转换为const应该是安全的。但是,另一种方法是引入未定义的行为(const为非const)。

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