C++ 我可以将char*缓冲区强制转换为对象类型吗?

C++ 我可以将char*缓冲区强制转换为对象类型吗?,c++,memory,constructor,casting,C++,Memory,Constructor,Casting,我问这个问题是出于好奇,而不是出于困难,因为我总是从你那里学到,即使是在不相关的话题上 >,考虑下面的方法,用C++编写,与G++连接。此方法运行良好,因为所有内容都已初始化为正确的大小 extern "C" { void retrieveObject( int id, char * buffer ) { Object::Object obj; extractObject( id, obj ); memcpy( buf

我问这个问题是出于好奇,而不是出于困难,因为我总是从你那里学到,即使是在不相关的话题上

>,考虑下面的方法,用C++编写,与G++连接。此方法运行良好,因为所有内容都已初始化为正确的大小

extern "C" 
  {
    void retrieveObject( int id, char * buffer )
      {
        Object::Object obj;

        extractObject( id, obj );
        memcpy( buffer, &obj, sizeof(obj) );
      }
  }

// Prototype of extractObject
const bool extractObject( const int& id, Object::Object& obj ) const;
现在,我希望避免声明本地
对象
和使用
memcpy

我试图用如下内容替换
retrieveObject

void retrieveObject( int id, char * buffer )
  {
    // Also tried dynamic_cast and C-Style cast
    extractObject( id, *(reinterpret_cast<Object::Object *>(buffer)) );
  }
void retrieveObject(int-id,char*buffer)
{
//还尝试了动态_cast和C样式cast
提取对象(id,*(重新解释强制转换(缓冲));
}
它成功编译并链接,但立即崩溃。考虑到我的缓冲区足够大,可以容纳<代码>对象< />代码,C++是否需要调用构造函数来“塑造”内存?是否有其他方法来替换局部变量和memcpy


我希望我的回答足够清楚,提前谢谢你

这可能会有很多问题-首先,如果您使用本地对象,您不能只构造它,然后在其上写入其他实例的内存(这只适用于POD类型,因为它们不需要调用析构函数),否则很可能会发生严重的内存泄漏

但这不是主要问题——根据所使用对象的类型,您提供的解决方案可能有效,也可能无效。它适用于简单的POD类型,甚至可能适用于更复杂的类(前提是您能够正确处理构造函数/析构函数调用),但当程序的某些其他部分希望对象位于其原始位置时,它将中断—比方说,您有一个类,它有两个成员变量:

struct A {
   int i;
   int * pi;
}

如果“pi”始终指向“i”成员,则如果将该对象“memcpy”到其他位置,它将很容易断开。

您所做的是有效地序列化
对象
,并且只有当
对象
中的所有数据连续存储时,才能正常工作。对于简单对象,这可以正常工作,但一旦有对象包含指向其他对象的指针,这就停止工作

<>在C++中,对象包含其他对象是非常常见的。
std::string
就是一个很好的例子。
string
类是一个容器,它引用存储在别处的引用计数器对象。因此,除非您确定对象是简单的连续对象,否则不要这样做。

您应该查看或。C++对象包含更多的运行时特定的数据()。
在模块之间传输对象时,还应考虑添加有关对象的版本信息。

如果要了解对象崩溃的原因和位置,请使用调试器。代码看起来很好

如果要避免中间对象实例,只需避免它即可。使
extractObject()
返回一个指向对象的指针,并使用该指针指向
memcpy()
其内容到
缓冲区


然而,要小心,正如另一个人所说,如果你只是重新解释对象的
缓冲区
如果对象不够简单,事情可能会破裂。

在你的第一次努力中

void retrieveObject( int id, char * buffer )
{
     Object::Object obj;
     extractObject( id, obj );
     memcpy( buffer, &obj, sizeof(obj) );
} 
void retrieveObject( int id, char * buffer )
{
     extractObject( id, *(reinterpret_cast<Object::Object *>(buffer)) );
} 
…您仍然让编译器创建局部变量obj,以保证正确对齐。在第二次努力中

void retrieveObject( int id, char * buffer )
{
     Object::Object obj;
     extractObject( id, obj );
     memcpy( buffer, &obj, sizeof(obj) );
} 
void retrieveObject( int id, char * buffer )
{
     extractObject( id, *(reinterpret_cast<Object::Object *>(buffer)) );
} 
void retrieveObject(int-id,char*buffer)
{
提取对象(id,*(重新解释强制转换(缓冲));
} 
…您向编译器承诺缓冲区指向一个字节,该字节针对Object::Object进行了适当对齐。但会吗?考虑到您的运行时崩溃,可能不会。通常,char*s可以从任何给定的字节开始,因为更复杂的对象通常与字大小对齐,或者与它们的数据成员所需的最大对齐。读取/写入int、double、指针等。Object::Object内部可能只有在内存正确对齐时才能工作-这取决于您的CPU等,但在UNIX/Linux上,未对齐可能会产生例如SIGBUS或SIGSEGV信号

为了解释这一点,让我们考虑一个简单的CPU /内存体系结构。假设在任何给定操作中,内存允许从地址0-3、4-7或8-11等读取4字节(32位体系结构),但无法读取地址1-4、2-5、3-6、5-8处的4字节卡盘。。。。听起来很奇怪,但这实际上是一个常见的内存限制,所以只接受它,并考虑后果。如果我们想在内存中读取一个4字节的数字-如果它位于这些4个地址中的一个,我们可以在一个内存中读取它,否则我们必须读取两次:从一个包含部分数据的4字节区域读取,然后从另一个包含其余数据的4字节区域读取,然后扔掉我们不想要的位,将其余的重新组装到适当的位置,将32位值放入CPU寄存器/内存。这太慢了,所以语言通常会注意将我们想要的值放在内存可以在一次操作中访问它们的位置。甚至CPU的设计也有这样的期望,因为它们通常有直接对内存中的值进行操作的指令,而无需显式地将它们加载到寄存器中(即,这是一个甚至低于汇编/机器代码级别的实现细节)。要求CPU对未对齐的数据进行操作的代码通常会导致CPU生成中断,操作系统可能会将其显示为信号


也就是说,关于在非POD数据上使用此数据的安全性的其他警告也是有效的。

问题是,您为什么要这样做?这样的事情在C++中几乎从来都不是必需的。(如果要序列化到文件或网络通信,这不是进行序列化的方式。)对象创建应该涉及构造函数。在构造函数中使用缓冲区。我想知道为什么extractObject()的返回类型是
const bool
,为什么它将
const int&
作为参数之一