2012-03-17 20 views
0

是否有任何编译器的标准布局类型的布局要求也不适用于普通可复制类型?特别是,关键规则是指向该类型的指针是指向其第一个成员的指针(其中基类将被视为在派生类之前出现)。也就是说,该类型的地址与其基本类型是相同的地址。Trivially始终可伪造的伪标准布局?

在代码中,是否有任何常见的编译器,其中以下实际上不会工作。对我来说这似乎很常见,所以我很惊讶它在C++ 11中没有标准化。我知道肯定这在GCC中有效,我相信它在MSVC中工作(尽管我可能是错的)。在哪个非历史编译器中,上述内容不能按预期工作?


扩展示例

上面的例子显示了基本的问题,但可能不会显示,会得到一个有意图。这是一个稍微冗长的例子。基本上任何人都可以调用“发送”来排队消息,然后稍后会通过回退到其实际类型来发送每条消息。

struct header { int len, id; } 
struct derived : public header { int other, fields; } 

void send(header * msg) 
{ 
    char * buffer = get_suitably_aligned_buffer(msg->len); 
    memcpy(buffer, msg, msg->len); 
} 

void dispatch(char * buffer) 
{ 
    header * msg = static_cast<header*>(buffer); 
    if(msg->id == derived_id) 
    handle_derived(static_cast<derived*>(msg)); 
} 


derived d; 
d.len = sizeof(d); 
d.id = deirved_id; 
send(&d); 

... 
char * buffer = get_the_buffer_again(); 
dispatch(buffer); 

它仍然省略了许多方面,但关键部分显示。

+6

是什么让你认为'memcpy'ing对象是C++中的“常见做法”? – 2012-03-17 17:20:05

+3

我不明白你为什么要使用赋值操作符来做其他操作?我很少看到C++ – 111111 2012-03-17 17:21:31

+0

@LightnessRacesinOrbit中的memcpy,因为我已经在很多代码中看到了它。此外,该标准提供了'memcpy'ing对象的规则,但并不能保证这种确切的情况。 – 2012-03-17 17:22:06

回答

1

是的,只要单一继承存在,人们就一直用C++来做这件事。是的,这基本上是合理的。不,这个标准不支持。它是普遍支持的吗?可能吧,但你已经知道那不是重点。这种问题是标准化应该消除的问题。

无论好坏,C++都提供了解决这个问题的办法,尽管它明显不那么优雅。

问题是,派生类中的非静态数据成员不一定在基本成员之后跟随相同的填充,就好像它们直接拼接到基本中一样。

但标准布局结构的union具有共同的初始序列(故意避免继承)确实收到此保证。

struct header { int len, id; } 

union derived { 
    struct { 
     header h; 
     int payload; 
    } fmt1; 

    struct { 
     header h; // repetitive 
     double payload; 
    } fmt2; 

    // etc for all message types 
}; 

布局可能实际上不同空时基类乘法包括,尤其是,如果第一非静态数据成员是相同类型的空基类。继承(仍然)不能做到这一点的原因可能是他们厌倦了编写空基的特例。

+0

我知道布局可能不同于伪基础作为fisrt成员,而不是(通过填充),但我很好。我希望避免这个解决方案,因为你指出的确切原因,它并不优雅。特别是因为我没有试图与另一种语言沟通,这完全是C++到C++。谢谢。 – 2012-03-18 05:41:24

1

我知道肯定这在GCC中有效,我相信它在MSVC中工作(尽管我可能是错的)。

不,你不知道。你已经在这些编译器上运行了一些不会中断的例子。这不同于知道“肯定”任何东西。

未定义的行为未定义。 GCC的下一个版本可能会破坏你的代码。 Visual Studio的下一个版本可能会破坏你的代码。的确,编译版本或者某些优化可能会破坏你的代码。

遵循该标准是唯一可以“确切知道”任何关于您所得到的方法。做你正在做的事情不是实现定义的行为;这是undefined的行为。所以你不能相信你会得到一个合理的答案,即使它出现工作。

+0

是的,它保证了标准布局,但我的类型只是可复制的,因此保证不成立。这就是为什么我感到惊讶,差别非常小我不明白为什么保证不是为那些可以复制的类型。 – 2012-03-17 18:20:34

+0

@ edA-qamort-ora-y:你的类型*不是*标准布局的方式是什么? – 2012-03-17 18:21:26

+0

这个例子显然是非常基本的,它没有表现出意图,只是潜在的问题。我不使用char *的原因是因为实际的'copy'函数使用'base'类指针中的一些数据(在我的情况下,这个长度实际上是一个成员变量)。 – 2012-03-17 18:22:46