首页 > 解决方案 > 在现有缓冲区上放置新的

问题描述

第一个问题,希望我设法说对了。

在检查是否可以“强制”缓冲区作为类(具有继承和 vptr)时,我尝试了以下代码:

我定义了以下类:

class a
{
    public:

    char strBuff[50];
    virtual void boo() = 0;

};

class b : public a
{
    public:
    virtual void boo()
    {
        printf("%s\n", strBuff);
    }
};

并像这样使用它们:

int main()
{
    char buffer_allo[100] = "123456789abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz";

    b* obj_Ptr = (b*)(buffer_allo);

    // Placement new
    new (obj_Ptr) b();

    // Calling virtual function
    obj_Ptr->boo();

    return 0;
}

程序的输出是空的,就像在\0缓冲区中一样,我不知道为什么。

我认为这是一个默认初始化\值初始化问题,并且确实将位置 new from 更改new (obj_Ptr) b();new (obj_Ptr) b; 并没有给出空白输出,而是仅覆盖前 8 个字符的缓冲区(可能由 vptr) ,

但是后来,我尝试向任一类添加构造函数,发现向 b 类添加空构造函数也会阻止缓冲区被初始化\0,但向 a 类添加构造函数似乎没有效果。

为什么会这样?这真的是初始化问题吗?如果是这样,为什么添加一个空的构造函数可以解决它?还是编译器\c++ 标准问题?

标签: c++new-operator

解决方案


嗯,这就是 C++ 初始化规则的黑暗区域。它们非常复杂,您可以在 cppreference 中阅读它们。

基本上,当您调用placement new - new (obj_Ptr) b();(带有一对空括号)时,会发生值初始化。根据标准:

1) 如果 T 是一个没有默认构造函数或有用户提供或删除的默认构造函数的类类型,则该对象是默认初始化的;

2) 如果 T 是一个类类型,其默认构造函数既不是用户提供也不是被删除(也就是说,它可能是一个具有隐式定义或默认的默认构造函数的类),则该对象被零初始化,然后它是如果它具有非平凡的默认构造函数,则默认初始化;

3) 如果 T 是数组类型,则数组的每个元素都是值初始化的;

4) 否则,对象被零初始化。

由于它是零初始化的,这就是您在调用obj_Ptr->boo();. 当您定义自己的构造函数时,该对象是默认初始化的,因此您的缓冲区包含垃圾。基本上就是这样。更详细的解释:cppreference中的值初始化

另外,与问题无关,但我想提几件事。

1)正如 Slava 指出的那样,最好直接使用 return fromplacement new ,而不需要任何强制转换,如下所示:auto obj_Ptr = new(buffer_allo) b();

2) 尽量避免virtual使用派生类方法的关键字。最好使用override,因为当您在派生类中意外创建新函数而不是覆盖基类中的新函数时,它更清晰并且可以捕获错误。像这样:void boo() override{...}


推荐阅读