我怎么能明智地超载贴装操作员新?

时间:2010-09-09 08:47:46

标签: c++ visual-c++ memory-management operator-overloading

C ++允许重载operator new - 全局和每个类 - 通常operator newoperator new[]分别与new[]语句和展示位置operator new一起使用。

这三个中的前两个通常因使用自定义分配器和添加跟踪而过载。但是放置operator new似乎很简单 - 它实际上什么也没做。例如,在Visual C ++中,默认实现只返回传递给调用的地址:

//from new.h
inline void* operator new( size_t, void* where )
{
   return where;
}

它还能做什么?为什么以及如何明智地超载展示位置operator new

9 个答案:

答案 0 :(得分:16)

正确的答案是您无法替换新的运营商展示位置

  

§18.4.1.3安置表格
  这些函数是保留的,C ++程序可能无法定义替换标准C ++库中版本的函数。

基本原理:分配和释放运算符的唯一目的是分配和释放内存,因此当给定内存时,不应再做任何事情。 (该标准特别指出这些功能“故意不执行任何其他操作。”)

答案 1 :(得分:4)

从技术上讲,展示位置operator new是除了所需内存大小之外还需要其他参数的operator new

因此,new(std::nothrow) X使用展示位置operator newnew(__FILE__, __LINE__) X也是如此。

覆盖operator new(size_t, void*)的唯一原因可能是添加跟踪信息,但我认为对此的需求非常低。

答案 2 :(得分:3)

One example在Stroustrup的常见问题解答中。

答案 3 :(得分:1)

最明显的覆盖是复制此实现。

另一个明智的做法是添加一些检查(例如,验证请求区域内没有“绑定标记”)。

然而,我认为,只要你覆盖其他的(对于给定的类),由于名称查找的机制(或者不覆盖它以防止其使用,)重点超过你必须覆盖它。那也没关系,但这是一个有意识的决定。)

答案 4 :(得分:1)

为预留区域定义自己的内存管理是一个不错的用途。

对于相同的物理数据(不需要移动数据)具有不同的视图是其他间接使用。 它还允许您将结构化文件作为缓冲区上的字符读取,然后通过在缓冲区上定义该类的对象来叠加其逻辑结构。 这个东西与文件的内存映射相结合,可以大大提高性能。 内存映射硬件...... 所以,千件申请!

答案 5 :(得分:0)

我见过一个例子,其中两个参数new []被覆盖以返回预先填充作为附加参数传递的char的内存块。我不记得使用的原始代码(可能是memset()),但它在功能上是这样的:

#include <iostream>
#include <algorithm>
#include <new>
void* operator new [](size_t n, char c)
{
        char* p = new char[n];
        std::fill(p, p+n, c);
        return p;
}
int main()
{
        char* p = new('a') char[10];
        std::cout << p[0] << p[1] << ".." << p[9] << '\n';
}

虽然我猜这不会被称为“展示位置”,因为它不会执行展示位置。如果模板化它可能是有用的,它可以构建任何类型的数组,填充了作为第二个参数传递的对象的副本......但是,无论如何,我们都有容器。

答案 6 :(得分:0)

我不确定这个问题,但是以下内容覆盖了班级级别的新位置:

struct Bar {
void* operator new(size_t /* ignored */, void* where) throw() { return where; }
};

int main() {
  char mem[1];
  Bar* bar = new(mem) Bar;
}

我相信这是合法的C ++(并且使用gcc 4.4.6编译并运行良好)。

您可以根据需要随意更改此运算符的实现(包括删除throw()子句,这意味着编译器在调用构造函数之前不再检查where指针的null 。尽管小心。但

§18.4.1.3很有意思。我相信这只适用于全局运算符的新函数,而不是特定于类的函数。

答案 7 :(得分:0)

放置新重载的最重要的额外功能是检查地址对齐。

例如,假设某些类需要16字节对齐。开发人员重载新的,新的[],删除和删除[] - 只是为了确保所有内容都正确对齐。

当他试图将他的类用于使用放置新的库的时候,一切正常。图书馆不知道是否需要/什么对齐类和地址它试图“放置”对象可能不一致 - 大繁荣。

这种情况的最简单的例子 - 尝试使用std :: vector&lt; T&gt;其中T需要非标准对齐。

对于placement new的重载允许检测指针是否未对齐 - 可能会节省数小时的调试时间。

答案 8 :(得分:-1)

我的主要用途是创建大量对象。它的性能要好得多,并且在整个块中分配内存的开销较小,即使用Win32中的VirtualAlloc(编程窗口时)。然后,您只需将该块中的ptr传递给每个对象放置,例如:

char *cp = new char[totalSize];

for(i = 0; i < count; i++, cp += ObjSize)        
{                                                        
    myClass *obj = new(cp) myClass;             
}