【问题标题】:Placement deallocation function is not called不调用放置释放函数
【发布时间】:2014-07-29 15:23:22
【问题描述】:

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

#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.
}

demo

5.3.4/22 说 N3797:

放置释放函数的声明与 一个布局分配函数的声明,如果它有相同的 参数的数量,并且在参数转换 (8.3.5) 之后,所有 除了第一个参数类型是相同的。如果查找发现 单个匹配释放函数,该函数将被调用; 否则,不会调用释放函数。

C++11中没有实现还是我的理解有误?

【问题讨论】:

  • 我以为只有在对象构建过程中出现异常时才会调用放置释放函数? Live example
  • @dyp 很好的例子!谢谢!我只是不知道 ecatmur 和 T.C. 引用的限制

标签: c++ c++11 memory-management


【解决方案1】:

如果提供了特定于类的解除分配函数,则没有以作用域解析运算符为前缀的 delete-expression 是格式错误的,除非具有一个或两个参数的特定于类的解除分配函数是可用:

10 - 如果类型是完整的,并且如果释放函数查找找到只有一个指针参数的普通释放函数和一个同时具有指针参数和大小参数的普通释放函数,那么选择的释放函数应该是那个有两个参数。否则,选择的释放函数应该是一个参数的函数

所以你需要:

  • 提供void operator delete[](void*);,
  • 提供void operator delete[](void*, size_t);,或
  • ::delete[] a

【讨论】:

  • §12.5 [class.free]/p4 可能更相关。 “如果查找的结果不明确或无法访问,或者查找选择了一个放置解除分配函数,则程序是非良构的。”
【解决方案2】:
A *a = new(5, 5) A[10]; 
A::operator delete[](a,5,5);

在 Visual C++ 2013 上效果很好

【讨论】:

  • 它与标准相矛盾。
  • @DmitryFucintv 这个 sn-p 到底有什么与标准相矛盾的?
  • @dyp 对不起。这是我的疏忽。似乎是一个参数传递给了删除表达式。
  • 嗯,不用担心,我花了 2 天时间思考我在那里做错了什么
【解决方案3】:

如果您想访问operator delete 中的原始放置新参数,则必须将它们存储在分配的内存块中并稍后检索它们。例如(Live at 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);
}

【讨论】:

    猜你喜欢
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 2021-10-23
    • 1970-01-01
    相关资源
    最近更新 更多