非指针变量和类成员上的新放置

非指针变量和类成员上的新放置

本文介绍了非指针变量和类成员上的新放置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例:

#include <iostream>

struct A {

    int i;

    A(int i)
    {
        this->i = i;
    }

    A &operator=(const A &a) = delete;
    A(const A &a) = delete;
};

int main()
{
    A a(1);
    new(&a) A(5);
    //a = A(7); // not allowed since = is deleted in A
    std::cout << a.i << std::endl;
}

这是一个使用placement new运算符的简单示例.由于struct A的副本构造函数和赋值运算符已被删除(无论出于何种原因),因此无法更改变量A a所保存的对象,除非将其地址传递给placement new运算符.

This is a simple example using the placement new operator. Since the copy constructor and assignment operator of struct A have been deleted (for whatever reason), it is not possible to change the object the variable A a holds, except for passing its address to the placement new operator.

这样做的原因可能是struct A拥有大型数组(例如100M条目),这些数组必须在赋值运算符和复制构造函数中进行复制.

Reasons for this might include that struct A holds large arrays (e.g. 100M entries) which would have to be copied in the assignment operator and the copy constructor.

问题的第一部分围绕这种方法的合法性".我发现了这个 stackoverflow问题,其可接受的答案是

The first part of the question revolves around the "legality" of this approach. I found this stackoverflow question, the accepted answer of which says

为什么会这样呢?我还看到了其他一些关于放置new运算符的示例,这些示例始终类似于

Why would that be the case? I have seen several other examples for the placement new operator, which are always similar to

A a(1);
A *b = new(&a) A(2);
// Now use *b instead of a

根据我的理解,使用A a还是A *b来访问对象都没有关系,因为新放置会替换A a地址(当然 A a.也就是说,我希望总是 b == &a.也许答案还不够清楚,并且此限制是由于类成员的稳定性所致.

From my understanding it should not matter whether A a or A *b is used to access the object since the placement new replaces the object at the address of A a which of course is A a. That is, I would expect that always b == &a. Maybe the answer was not clear enough and this limitation is due to the const-ness of the class member.

这里是具有相同想法的另一个示例,但是这次struct A被嵌入到另一个对象中:

Here is another example with the same idea, however this time struct A is embedded into another object:

#include <iostream>

struct A {

    int *p;

    A(int i)
    {
        p = new int(i);
    }

    ~A()
    {
        delete p;
    }

    A &operator=(const A &a) = delete;
    A(const A &a) = delete;
};

struct B {

    A a;

    B(int i) : a(i)
    {
    }

    void set(int i)
    {
        a.~A(); // Destroy the old object
        new(&a) A(i);
    }

};

int main()
{
    B b(1);
    b.set(2);
    std::cout << *(b.a.i) << std::endl;
    // This should print 2 and there should be no memory leaks
}

问题与相同的推理基本相同.重新放置到地址&a是否有效?

The question is basically the same with the same reasoning. Is it valid to placement-new into the address &a?

推荐答案

对于此特定代码,您还可以,并且可以使用a引用放置在其上的新对象. [basic.life]/8

For this specific code, you are okay and can use a to refer to the new object that you put in its place. This is covered by [basic.life]/8

  • 新对象的存储空间正好覆盖了原始对象所占据的存储位置,并且

  • the storage for the new object exactly overlays the storage location which the original object occupied, and

新对象与原始对象具有相同的类型(忽略顶级cv限定词),并且

the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and

原始对象的类型不是const限定的,并且,如果是类类型,则不包含任何类型为const限定的非静态数据成员或引用类型,并且

the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

原始对象和新对象都不是潜在重叠的子对象([intro.object]).

neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).

您选中了所有这些要求,因此a将引用新的"您放置在a内存中的A.

You check off all of those requirements so a will refer to the "new" A that you placed in a's memory.

这篇关于非指针变量和类成员上的新放置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 17:21