放置释放函数未被调用

8

我写的以下代码必须调用放置删除和分配函数。

#include <iostream>
using namespace std;

struct A
{
    void * operator new [] (size_t t, int, int)
    {
        cout << "3 parameters allocation" << endl;
        return ::operator new[](t);
    }

    void operator delete [] (void *p, int, int)
    {
        cout << "3 parameters deallocation" << endl;
        return ::operator delete[](p);
    }
};

int main() 
{
    A *a = new (5,5) A[10]; //operator new [] (size_t, int, int) invoked
    delete [] a; //Error. Overload resolution is failed.
}

演示

根据 N3797 版本 5.3.4/22 规定:

如果一个底层释放函数的声明与已有的底层分配函数的声明相匹配,那么这个底层释放函数的声明必须和对应的底层分配函数的声明一致。通过转换参数(8.3.5),除去第一个参数外,所有参数类型必须都相同。如果查找到一个匹配的释放函数,则调用该函数;否则,不会调用任何释放函数。

这在 C++11 中是否实现了?还是我理解有误?


5
我认为这个放置释放函数只有在对象构造期间出现异常时才会被调用?Live example - dyp
相关链接:https://dev59.com/ym025IYBdhLWcg3wsIEU#14119344 - dyp
@dyp 不错的例子!谢谢!我只是不了解 ecatmur 和 T.C. 提到的限制。 - user2953119
3个回答

9
如果提供了特定类别的释放函数,则未使用作用域解析运算符前缀的delete-expression是不合法的,除非具有一个或两个参数的特定类别的释放函数可用:

10 - 如果类型是完整的,并且如果释放函数查找既有仅具有指针参数的通常释放函数,也有同时具有指针参数和大小参数的通常释放函数,则所选的释放函数应该是具有两个参数的函数。否则,所选的释放函数应该是具有一个参数的函数

因此,你需要执行以下操作之一:
  • 提供void operator delete[](void*);
  • 提供void operator delete[](void*, size_t);,或者
  • 编写::delete[] a

5
§12.5 [class.free]/p4 可能更相关。"如果查找结果不明确或无法访问,或者如果查找选择了一个放置解除函数,程序将是非法的。" - T.C.

1
A *a = new(5, 5) A[10]; 
A::operator delete[](a,5,5);

在 Visual C++ 2013 上,这个很有效。

它与标准相矛盾。 - user2953119
@DmitryFucintv 这段代码片段中到底有什么与标准相矛盾的地方? - dyp
@dyp 对不起,是我的疏忽。似乎将一个参数传递到了删除表达式中。 - user2953119
没关系,我花了两天时间思考我在那里可能做错了什么。 - Giobunny

1

如果您想在operator delete中访问原始的placement new参数,则需要将它们存储在分配的内存块中,并稍后检索。例如(在Ideone上实时查看):

struct A
{
    static void * operator new [] (size_t t, int first, int second);
    static void operator delete [] (void *p, size_t t);
    static void operator delete [] (void *p, int first, int second)
    {
        cout << "3 parameters deallocation: " << first << ", " << second << endl;
        return ::operator delete[](p);
    }
};

// simple POD struct to store the placement parameters
struct info {
    int first_param, second_param;
};

void* A::operator new [] (size_t t, int first, int second)
{
    cout << "3 parameters allocation: " << first << ", " << second << endl;
    // allocate sizeof(info) extra space to store the parameters
    auto const p = ::operator new[](t + sizeof(info));
    auto const pinfo = reinterpret_cast<char*>(p) + t;
    auto const tmp = info{first, second};
    std::copy_n(reinterpret_cast<const char*>(&tmp), sizeof(info), pinfo);
    return p;
}

static void A::operator delete [] (void *p, std::size_t t) {
    // retrieve the parameters that we stored in operator new [].
    auto const pinfo = reinterpret_cast<const char*>(p) + t;
    auto tmp = info{};
    std::copy_n(pinfo, sizeof(info), reinterpret_cast<char*>(&tmp));
    cout << "Deleting with original parameters: " << tmp.first_param << ", " << tmp.second_param << endl;
    ::operator delete[](p);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接