代码之家  ›  专栏  ›  技术社区  ›  Lingxi

删除未使用新表达式构造的对象实际上可以吗?

  •  7
  • Lingxi  · 技术社区  · 6 年前

    迂腐地说,这可能不好。根据 cppref :

    如果 表示 是其他任何内容,包括如果它是通过新表达式的数组形式获得的指针,则行为未定义。

    撇开这一点不谈,下面的代码在实践中可以吗( T 为非数组,并假设 new 是否未更换)?

    auto p = (T*)operator new(sizeof(T));
    new(p) T{};
    delete p;
    

    据说在 cppref 那个

    调用分配函数时,新表达式传递 作为第一个参数请求的字节数,类型为 std::size_t ,这正是 sizeof(T) 对于非阵列T。

    所以我想这可能没问题。然而,据说自C++14以来,

    允许新表达式删除或合并所做的分配 通过可更换的分配功能。如果省略,则 编译器可以提供存储,而无需调用 分配功能(这也允许优化未使用的 新表达式)。在合并的情况下,由 可以扩展新表达式E1,以便为 如果以下所有条件均为真,则另一个新表达式E2:[…]

    请注意,只有在新表达式 用于调用可替换分配函数,而不是任何其他方法: delete[] new int[10]; 可以进行优化,但是 operator delete(operator new(10)); 不能

    我不太清楚其中的含义。那么,这在C++14中可以吗?

    我为什么要问这个问题? ( source )

    有时,内存分配和初始化不能在一个步骤中完成。 您必须手动分配内存,执行其他操作,然后初始化对象, e、 g.,以提供强大的异常安全性。 在这种情况下,如果无法在生成的指针上使用delete表达式,则必须手动取消初始化和取消分配,这很繁琐。 更糟糕的是,如果同时使用新表达式和手动方法, 您必须跟踪每个对象使用的对象。

    2 回复  |  直到 6 年前
        1
  •  4
  •   T.C. Yksisarvinen    6 年前

    如果您 p = new(p) T{}; ,假设没有使用自定义(de)分配功能。(它可以很容易地针对这些事情进行强化;这样做是留给读者的练习。)

    规则是必须给出非数组 delete 指向由非数组创建的对象的指针 new (或此类对象的基类(带有虚拟析构函数)子对象,或空指针)。通过这种更改,您的代码可以做到这一点。

    不要求非数组 属于非安置形式。不可能,因为您最好能够删除 new(std::nothrow) int 。这是一个位置 新建表达式 同样,即使人们在谈论“新位置”时通常不是这个意思。

    删去 定义为导致调用解除分配函数(忽略省略情况,这在这里无关紧要,因为 新建表达式 不是可替换的全局分配函数)。如果您将事情设置为将无效参数传递给该释放函数,则会得到未定义的行为。但在这里,它传递了正确的地址(如果使用了大小释放函数,则传递了正确的大小),因此定义良好。

        2
  •  -3
  •   Red.Wave P.W    6 年前

    我没有完全理解OP的最后一段。显式调用析构函数,然后释放指针,有什么烦人的?这就是STL和我见过的任何著名的lib一直在做的事情。是的,您必须跟踪如何分配内存,以便重新分配内存。阅读std::vector和/或std::shared\u ptr的api文档可以熟悉正确的操作方法。 如果您不熟悉显式dtor调用的语法,这里有一个简单的代码片段:

    void * raw_ptr= my_alloc(sizeof(my_type),alignof(my_type));
    if (!raw_ptr)
         throw my_bad_alloc();
    my_type* ptr {new(raw_ptr) my_type{init_params}};
    raw_ptr=nullptr;
        //...
    ptr->~my_type();//hello! Is it me you're lookin' for?
    if (!my_dealloc(ptr))
         throw my_runtime_error();
    ptr=nullptr;