【问题标题】:Deallocation function precludes use of an allocation with two parameter重新分配功能排除使用具有两个参数的分配
【发布时间】:2014-09-14 12:33:33
【问题描述】:

这里来自 3.7.4.2 N3797:

全局运算符 delete[] 正好有两个参数,第二个 其中的 std::size_t 类型是一个常用的释放函数。37

37) 此释放函数排除了分配函数的使用 void operator new(std::size_t, std::size_t) 作为布局分配 功能

这个注释对我来说不是很清楚。我想看看这种排除的真实例子。编译器会抛出警告还是我们有运行时错误?我一直在尝试写如下内容:

using std::cout;
struct A
{
    int a;
    A(){ a = 5; }
    void * operator new(std::size_t t, std::size_t)
    {
        void *p = ::operator new(t);
        return p;
    }
};

int main(){ }

而且我不知道反映这种排除的示例。你能帮我提供一个吗?

【问题讨论】:

  • 你写的是 new[] 的重载,忽略了第二个参数并像 new 一样有效地工作
  • @meneldal 你的意思是void * operator new(std::size_t t, std::size_t) 是new[] 的重载还是别的什么?
  • 我的意思是你写的新 new[]new 做同样的事情:你只是分配一个值而不是一个数组
  • @meneldal 我不明白你的意思。我没有写我自己的new[]。我写了new
  • 但是delete[] 是您在new[] 之后的名称,对吗?我想我对此感到困惑。但如果只是放置new,则不应在其中分配内存,因为内存已分配,您只应构造对象。

标签: c++ memory-management


【解决方案1】:

如果构造函数在 new 调用期间抛出异常,则将调用具有相同参数的类似声明的 delete。因此,placement new 和 delete 应始终成对声明。

在这种情况下,删除将与数组删除具有相同的签名,编译器将无法在它们之间进行选择。

编辑添加示例代码和输出。

您的代码没有实现被禁止的全局数组放置新:

void * operator new( size_t bytes, size_t )

此程序将说明如何调用全局 new 和 delete。

#include <stdint.h>
#include <malloc.h>
#include <iostream>
#include <stdexcept>

using namespace std;

struct A
{
    int a;

    A( void )
        : a( 1 )
    {
        cout << __LINE__ << " : A::A()" << endl;
        throw logic_error( "That is .. illogical" );
    }
};

// Placement new with size_t parameter
void * operator new( size_t bytes, size_t )
{
    cout << __LINE__ << " : void * A::operator new( size_t bytes = " << bytes << ", size_t )";
    void *p = malloc( bytes );
    cout << " -> " << p << endl;
    return p;
}

// C++11 : Array placement delete with size_t parameter
// C++14 : Array delete
void operator delete( void *p, std::size_t n ) 
{
    cout << __LINE__ << " : void A::operator delete( void *p = " << p << ", size_t n = " << n << " )" << endl;
    if (p)
        free( p );
}

// Non-array new
void * operator new( size_t bytes )
{
    cout << __LINE__ << " : void * A::operator new( size_t bytes = " << bytes << " )";
    void *p = malloc( bytes );
    cout << " -> " << p << endl;
    return p;
}

// Non-array delete
void operator delete( void *p ) noexcept
{
    cout << __LINE__ << " : void A::operator delete( void *p = " << p << " )" << endl;
    if (p)
        free( p );
}

// Array new
void * operator new[]( size_t bytes )
{
    cout << __LINE__ << " : void * A::operator new[]( size_t bytes = " << bytes << " )";
    void *p = malloc( bytes );
    cout << " -> " << p << endl;
    return p;
}

// Array placement new with size_t parameter
void * operator new[]( size_t bytes, size_t n )
{
    cout << __LINE__ << " : void * A::operator new[]( size_t bytes = " << bytes << ", size_t n = " << n << " )";
    void *p = malloc( bytes );
    cout << " -> " << p << endl;
    return p;
}

// C++11 : Array placement delete with size_t parameter
// C++14 : Array delete
void operator delete[]( void *p, std::size_t n ) 
{
    cout << __LINE__ << " : void A::operator delete[]( void *p = " << p << ", size_t n = " << n << " )" << endl;
    if (p)
        free( p );
}

int main( int, char ** )
{

    A *p = nullptr;
#if 1
    try
    {
        cout << __LINE__ << " : ===== Array placement new allocate with size_t parameter. =====" << endl;
        p = new( (size_t)4 ) A[ 3 ];

        cout << __LINE__ << " : ===== Array placement new succeeded. =====" << endl;
    }
    catch (...)
    {
    }

    cout << __LINE__ << " : ===== Array placement delete. =====" << endl;
    delete[] p;
    p = nullptr;

#endif

    try
    {
        cout << __LINE__ << " : ===== Array new. =====" << endl;
        p = new A[ 3 ];

        cout << __LINE__ << " : ===== Array new succeeded. =====" << endl;
    }
    catch (...)
    {
    }

    cout << __LINE__ << " : ===== Array delete. =====" << endl;
    delete[] p;
    p = nullptr;

    cout << __LINE__ << " : ===== Complete. =====" << endl;

    return 0;
}

使用 C++11 的 clang 3.4.2 编译得到以下结果:

$ clang++ --std=c++11 -o replace_new main.cpp && ./replace_new
88 : ===== Array placement new allocate with size_t parameter. =====
66 : void * A::operator new[]( size_t bytes = 12, size_t n = 4 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
76 : void A::operator delete[]( void *p = 0x80048358, size_t n = 4 )
49 : void A::operator delete( void *p = 0x800483d8 )
97 : ===== Array placement delete. =====
105 : ===== Array new. =====
57 : void * A::operator new[]( size_t bytes = 12 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
49 : void A::operator delete( void *p = 0x80048358 )
49 : void A::operator delete( void *p = 0x800483d8 )
114 : ===== Array delete. =====
118 : ===== Complete. =====

33 字节的分配是个例外。异常和数组都用同一个删除函数删除。

使用 C++14 规则编译会得到以下结果:

$ clang++ --std=c++1y -o replace_new main.cpp && ./replace_new
main.cpp:89:17: error: 'new' expression with placement arguments refers to non-placement 'operator delete'
            p = new( (size_t)4 ) A[ 3 ];
                ^    ~~~~~~~~~
main.cpp:74:10: note: 'operator delete[]' declared here
    void operator delete[]( void *p, std::size_t n )
         ^
1 error generated.

禁用无效部分并使用 C++14 规则编译会得到以下结果:

$ clang++ --std=c++1y -o replace_new main.cpp && ./replace_new
105 : ===== Array new. =====
57 : void * A::operator new[]( size_t bytes = 12 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
76 : void A::operator delete[]( void *p = 0x80048358, size_t n = 12 )
49 : void A::operator delete( void *p = 0x800483d8 )
114 : ===== Array delete. =====
118 : ===== Complete. =====

请注意,现在使用不同的删除函数删除了数组。当编译为 C++11 时,删除数组放置 new 的方法与第 76 行的删除函数相同。

【讨论】:

  • 您能否提供任何示例来改进您的答案?
猜你喜欢
  • 1970-01-01
  • 2011-03-07
  • 2010-11-11
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-22
  • 2018-09-18
相关资源
最近更新 更多