我想使用fwrite将对象写入顺序文件。班级就像是
class A{
int a;
int b;
public:
//interface
}
当我将对象写入文件时。我在徘徊,我可以使用fwrite( this, sizeof(int), 2, fo)
来编写前两个整数。
问题是:this
保证指向对象的开始 数据 ,即使可能在最开始时存在虚拟表物体。所以上面的操作是安全的。
答案 0 :(得分:5)
不,不是。您可以使用fwrite(&a, sizeof(int), 2, fo)
,但也不应该使用c
。在安全方面,漫步原始内存很少是一个好主意,因为你不应该依赖特定的内存布局。有人可能会在a
和b
之间引入另一个变量{{1}},而不会注意到他正在破坏您的代码。如果要访问变量,请明确执行此操作。不要只是访问你认为变量的内存或者你最后一次检查它们的位置。
答案 1 :(得分:4)
this
提供对象的地址,它不一定是第一个成员的地址。唯一的例外是所谓的标准布局类型。从C ++ 11标准:
(9.2 / 20)指向标准布局结构对象的指针(适当地使用
reinterpret_cast
转换)指向其初始成员(或者如果该成员是位字段,则指向其中的单位它驻留),反之亦然。 [注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐。 - 结束说明]
这是标准布局类型的定义:
(9/7)标准布局类是一个类:
- 没有类型为非标准布局类(或此类类型的数组)或引用的非静态数据成员,
- 没有虚函数(10.3),没有虚基类(10.1),
- 对所有非静态数据成员具有相同的访问控制(第11条),
- 没有非标准布局基类,
- 在大多数派生类中没有非静态数据成员,并且最多只有一个具有非静态数据成员的基类,或者没有带有非静态数据成员的基类,并且 - 没有与第一个非静态数据成员相同类型的基类。 [108][108] 这可确保具有相同类类型且属于同一最派生对象的两个子对象不在同一地址(5.10)分配。
请注意,对象类型不必是POD - 具有上面定义的标准布局就足够了。 (POD都有标准布局,但另外,它们是trivially constructible,可以轻松移动并且可以轻松复制。)
据我所知,您的类型似乎是标准布局(确保所有非静态数据成员的访问控制都相同)。在这种情况下,this
确实会指向初始成员。关于将其用于序列化的目的,标准实际上明确说明了:
(9/9)[注意:标准布局类对于与用其他编程语言编写的代码进行通信非常有用。它们的布局在9.2中规定。 - 结束说明]
当然,这并不能解决序列化的所有问题。特别是,您将无法获得序列化数据的可移植性(例如,由于字节序不兼容)。
答案 2 :(得分:1)
许多答案都正确地说“不”。下面是一些代码,用于说明为什么永远不能保证this
指向对象的开头:
#include <iostream>
class A {
public: virtual int value1() { std::cout << this << "\n"; }
};
class B {
public: virtual int value2() { std::cout << this << "\n"; }
};
class C : public A, public B {};
int main(int argc, char** argv) {
C* c = new C();
A* a = (A*) c;
B* b = (B*) c;
a->value1();
b->value2();
return 0;
}
请注意在虚拟方法中使用this
。
输出可以(取决于编译器)显示指针a
和b
是不同的。最有可能的是,a
将指向对象的开头,但b
则不会。当使用多重继承时,问题最容易出现。
答案 3 :(得分:0)
使用fwrite
将对象写入文件是一个非常糟糕的主意,原因有很多。
例如,如果您的类包含std::vector<int>
,那么您将保存指向整数的指针,而不是整数。
对于“更高级别”的原因(对齐,版本控制,二进制兼容性),在大多数情况下即使在C中也是一个坏主意,即使成员只是简单的本机类型。