我怎样才能明智地重载新的放置运算符?

发布于 2024-09-18 22:31:29 字数 462 浏览 6 评论 0原文

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

C++ allows overloading operator new - both global and per-class - usual operator new, operator new[] used with new[] statement and placement operator new separately.

The former two of those three are usually overloaded for using customized allocators and adding tracing. But placement operator new seems pretty straightforward - it actually does nothing inside. For example, in Visual C++ the default implementation just returns the address passed into the call:

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

What else could it do? Why and how could I sensibly overload placement operator new?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

等待圉鍢 2024-09-25 22:31:29

正确的答案是您无法更换新的操作员位置

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

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

The correct answer is you cannot replace operator placement new.

§18.4.​1.3 Placement forms
These functions are reserved, a C++ program may not define functions that displace the versions in the Standard C++ library.

The rationale: The only purpose of the allocation and deallocation operators is to allocate and deallocate memory, so when given memory nothing more should be done. (The standard specifically notes that these functions "Intentionally perform no other action.")

披肩女神 2024-09-25 22:31:29

从技术上讲,放置operator new是任何除了所需内存大小之外还接受其他参数的operator new

因此,new(std::nothrow) X 使用放置运算符 new,new(__FILE__, __LINE__) X 也是如此。

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

Technically, a placement operator new is any operator new that takes additional arguments besides the size of the memory needed.

So, new(std::nothrow) X uses a placement operator new and so does new(__FILE__, __LINE__) X.

The only reason for overriding the operator new(size_t, void*) could be to add tracing information, but I think the need for that will be pretty low.

夕色琉璃 2024-09-25 22:31:29

一个示例位于 Stroustrup 的常见问题解答中。

One example is at Stroustrup's FAQ.

月牙弯弯 2024-09-25 22:31:29

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

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

然而,我认为重点不仅仅是你必须重写它,一旦你重写了其他的(对于给定的类),因为名称查找的机制(或者不重写它以防止它的使用,这也很好) ,但这是一个有意识的决定)。

The most obvious override would be to copy this implementation.

Another sensible one would be to add some checks (for example, verifying that there is no "bound-marker" within the request zone).

I think however that the point is more than you HAVE to override it, as soon as you override the others (for a given class), because of the mechanics of name look up (or not overriding it to prevent its use, that's fine too, but it's a conscious decision).

薄情伤 2024-09-25 22:31:29

为保留区域定义您自己的内存管理是一种很好的用途。

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

To define your own memory management for a prereserved area is one nice use.

To have different views on the same physical data (no need to move the data) is other interseting use.
It also allows you reading a structured file as chars on a buffer and then, the superimposition of the their logical structure by defining an object of that the class over the buffer.
The combination of this thing with the memory mapping of files, can provide big improvements in performance.
The memory mapped hardware...
So, thousand applications!

旧伤慢歌 2024-09-25 22:31:29

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

例如,假设某个类需要 16 字节对齐。开发人员重载 new、new[]、delete 和 delete[] - 只是为了确保一切都正确对齐。

当他尝试将他的类与使用新放置的库一起使用时,一切都工作正常...库不知道该类是否需要/需要什么对齐,并且解决它尝试“放置”对象可能未对齐的问题- 大繁荣。

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

新的放置重载允许检测指针是否未对齐 - 可能会节省调试时间。

The most important extra-functionality for placement new overload would be to check address alignment.

For example, lets assume some class requires 16-byte alignment. Developer overloads new, new[], delete and delete[] - just to be sure everything is aligned properly.

Everything works fine to the moment when he tries to use his class with library which uses placement new... Library has no idea if/what alignment is required for the class and address it tries to "place" the object to might not be aligned - big boom.

The simplest example of such situation - try using std::vector<T> where T requires non-standard alignment.

Overload for placement new allows to detect if pointer is not aligned - might save hours of debugging.

坏尐絯 2024-09-25 22:31:29

我见过一个示例,其中两个参数 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';
}

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

I've seen an example where two-argument new [] was overwritten to return memory blocks pre-filled with the char passed as the additional argument. I don't remember what the original code used (probably memset()), but it was functionally something like this:

#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';
}

although I guess this wouldn't be called "placement" new because it does not perform placement. It could probably be useful if templated so that it can build arrays of any type, filled with a copy of the object passed as its second argument... but then, we have containers for that anyway.

静待花开 2024-09-25 22:31:29

我不太确定这个问题,但以下内容会覆盖类级别的 new 放置:

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 很有趣。我相信这仅适用于全局运算符新函数,而不适用于特定于类的函数。

I'm not exactly sure of the question, but the following overrides placement new at the class level:

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

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

I believe this is legal C++ (and compiles and runs fine with gcc 4.4.6).

You are free to change the implementation of this operator as you see fit (including removing the throw() clause, which will mean the compiler no longer checks the where pointer for null before calling the constructor). Tread carefully though.

§18.4.​1.3 is interesting. I believe this just applies to the global operator new function, not class specific ones.

雨后咖啡店 2024-09-25 22:31:29

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

char *cp = new char[totalSize];

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

My primary usage is to create a large array of objects. Its performing much better and has less overhead to allocate the memory in a whole block, i.e. using VirtualAlloc from Win32 (when programming windows). Then you just pass a ptr within that block to each objects placement new such as:

char *cp = new char[totalSize];

for(i = 0; i < count; i++, cp += ObjSize)        
{                                                        
    myClass *obj = new(cp) myClass;             
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文