这个operator new的重载有什么问题吗?

发布于 2024-09-12 09:08:45 字数 820 浏览 10 评论 0原文

我正在考虑我可能会编写的一些内存池/分配内容,因此我想出了这个 operator new 重载,我想用它来促进内存的重用。我想知道你们在我的实现(或任何其他可能的问题)中是否存在任何问题。

#include <cstddef>

namespace ns {
    struct renew_t { };
    renew_t const renew;
}

template<typename T>
inline void * operator new(std::size_t size, T * p, ns::renew_t renew_constant) {
    p->~T();
    return p;
}

template<typename T>
inline void operator delete(void *, T *, ns::renew_t renew_constant) { }

可以这样使用

int main() {
    foo * p(new foo());        // allocates memory and calls foo's default constructor
    new(p, ns::renew) foo(42); // calls foo's destructor, then calls another of foo's constructors on the same memory
    delete p;                  // calls foo's destructor and deallocates the memory
}

I was thinking about some memory pool/allocation stuff I might write so I came up with this operator new overload that I want to use to facilitate reuse of memory. I'm wondering if there are any problems you guys can think of with my implementation (or any other possible ones).

#include <cstddef>

namespace ns {
    struct renew_t { };
    renew_t const renew;
}

template<typename T>
inline void * operator new(std::size_t size, T * p, ns::renew_t renew_constant) {
    p->~T();
    return p;
}

template<typename T>
inline void operator delete(void *, T *, ns::renew_t renew_constant) { }

It can be used like this

int main() {
    foo * p(new foo());        // allocates memory and calls foo's default constructor
    new(p, ns::renew) foo(42); // calls foo's destructor, then calls another of foo's constructors on the same memory
    delete p;                  // calls foo's destructor and deallocates the memory
}

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

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

发布评论

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

评论(3

最冷一天 2024-09-19 09:08:45

请阅读http://www.gotw.ca/gotw/022.htmhttp://www.gotw.ca/gotw/023.htm

实际上,您应该定义 operator= 而不是用析构函数玩游戏。并且添加一个operator new(和operator delete,恶心!)重载到混合中只会增加痛苦。

而且,正如 C++ 大神 Herb Sutter 在这些链接中建议的那样,您可以简单地根据 operator= 定义构造函数。

Please read http://www.gotw.ca/gotw/022.htm and http://www.gotw.ca/gotw/023.htm.

Really, you should define operator= rather than playing games with destructors. And adding an operator new (and operator delete, YUCK!) overload into the mix only increases the pain.

And, as C++ god Herb Sutter recommends in those links, you can simply define constructors in terms of operator=.

饭团 2024-09-19 09:08:45

应该很好,只要你不尝试一些疯狂的事情并尝试更新子类。既然你说这是为了游泳池,那应该没问题。

也就是说,我唯一的问题是 - 什么更清晰?这是一个品味问题,但想象一下其他人可能需要查看代码。您基本上只是将两个简单且明显的语句收缩为一个需要更深入了解代码内部功能的语句。

在我的池函数中,我通常有两种单独的方法,一种用于销毁,一种用于构造,它们本质上都在执行您在此处所做的操作(p->~T 和 new(p) T()),但至少您知道他们就是这么做的。

SHOULD be good, as long as you don't try something crazy and try to renew a subclass. Since you said this is for a pool, it should be fine.

That said, my only question is - what is more legible? This is a question of taste, but imagine that somebody else might need to look at the code. You're basically just contracting two simple and obvious statements into one that requires deeper knowledge of what the code internally does.

In my pool functions, I typically had two separate methods, one to destroy and one to construct, both them essentially doing what you do here (p->~T and new(p) T()), but at least you know exactly what they did.

时光瘦了 2024-09-19 09:08:45

delete() 运算符不会调用对象的析构函数,这对我来说是出乎意料的。

我必须对 new(p, ns::renew) foo(42) 进行双重考虑。对我来说,这根本不直观。

您可能真正想要的是分离分配内存的过程和构造对象的过程。对于这种情况,您通常使用“placement new” 相反。

// Not exception safe!

void* p = ::operator new(sizeof(T)); // allocate raw memory

new(p) T(41); // construct a T at this memory location
p->~T();      // destruct T

new(p) T(42); // recreate a different T at the same memory location
p->~T();      // destruct T

::operator delete(p); // deallocate raw memory

在真实的内存池应用程序中,您可以将上述行包装到某种 MemoryPool 类。

当然,这只适用于您实际上直接处理内存以实现实际内存池或容器分配器的情况。在其他情况下,你会更好按照 Potatoswatter 的建议,重载 = 运算符()。

The delete() operator doesn't call the destructor of the object, which is unexpected to me.

I had to do a double take on new(p, ns::renew) foo(42). To me that's simply not intuitive.

What you probably really want is to seperate the process of allocating memory and the process of constructing objects. For situations like this, you typically use "placement new" instead.

// Not exception safe!

void* p = ::operator new(sizeof(T)); // allocate raw memory

new(p) T(41); // construct a T at this memory location
p->~T();      // destruct T

new(p) T(42); // recreate a different T at the same memory location
p->~T();      // destruct T

::operator delete(p); // deallocate raw memory

In a real memory pool application, you would wrap the above lines into a MemoryPool class of some sort.

Of course, this only applies if you're actually dealing with memory directly for the purpose of implementing an actual memory pool or an allocator of a container. In other situations, you're better off overloading the = operator() as suggested by Potatoswatter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文