重载新运算符

发布于 2024-11-24 21:52:45 字数 344 浏览 2 评论 0原文

是否可以重载 new 运算符,以便不创建对象,而是返回现有对象。

如果这是可能的,那么你如何才能首先创建对象:D

我知道这听起来很奇怪。我试图向客户隐瞒一些细节。我正在 PS2 上制作游戏,我想要使用 New Foo() 语法,但想要一个可以使用的预制对象列表。

我不认为可以规避这个问题,因为 new 运算符返回指向可用内存的指针。

new Foo;

struct Foo
{
    void* operator new(std::size_t)
    {
        // return pre made obj.
    }

};

Is it possible to overload the new operator so that an object isn't created, but instead return an existing object.

If that is possible, how could you create the objects in the first place :D

This sounds weird I know. I'm trying to hide some details from the client. I am making a game on PS2, I'd like to have the New Foo() syntax but want a list of premade objects that can be used instead.

I don't see to circumvent this as the new operator returns a pointer to available memory.

new Foo;

struct Foo
{
    void* operator new(std::size_t)
    {
        // return pre made obj.
    }

};

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

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

发布评论

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

评论(8

書生途 2024-12-01 21:52:45

据我所知,您无法更改 new 它实际构造对象的这一方面。重载运算符只是返回原始内存,然后语言会在该内存中自动构造对象。你无法控制这一步。

无论如何,如果您没有获得 new 对象,那么该语法的意义何在?

As far as I know, you can't change this aspect of new that it actually constructs the object. The overloaded operator just returns raw memory, and then the language constructs the object automatically in this memory. You don't control that step.

Anyway, if you don't get a new object, what would be the point of that syntax?

不醒的梦 2024-12-01 21:52:45

http://www.cplusplus.com/reference/std/ new/operator%20new%5B%5D/

应该告诉你所有你需要知道的!

或者甚至可能是这个

http://www.cplusplus.com/reference/std/ new/operator%20new/

operator new 是一个可以覆盖的全局函数。

不要忘记,如果您提供了一个 new 运算符,您还需要提供一个删除运算符。

我猜您正在尝试设置一个内存池,请记住实际测量有和没有的性能,因为恕我直言,它并不总是值得麻烦。

编辑:
阅读你的问题和其他一些答案的字里行间,我的猜测是你真的想单独保留重载的 new/delete 和单例模式。相反,请采用工厂模式方法。

您的所有代码都调用

SomethingStatic::GetNewWhatsit()

函数(而不是构造对象)
它返回数组中的下一个指针。指向您在程序初始化时以正常方式创建的对象的指针数组。

 whatsit* GetNewWhatsit()
 {
  if (num_of_objects > ARRAY_SIZE(whatsit_cache))
   return 0;
  else 
   return whatsit_cache[num_of_objects++];  // post inc. on purpose 
 }

http://www.cplusplus.com/reference/std/new/operator%20new%5B%5D/

Should tell you all you need to know!

or maybe even this

http://www.cplusplus.com/reference/std/new/operator%20new/

operator new is a global function which you can override.

Don't forget you need to also provide an operator delete, if you provide an operator new.

I'm guessing you are trying to set up a memory pool, remember to actually measure performance with and without, as its not always worth the hassle IMHO.

Edit:
Reading between the lines of your question and some of the other answers, my guess is you really want to leave overloading new / delete and singleton pattern alone. Instead go for a factory pattern approach.

All of your code calls a

SomethingStatic::GetNewWhatsit()

function, (instead of constructing the object)
which returns the next pointer in an array. An array of pointers to objects which you created in the normal way in the initialisation of your program.

 whatsit* GetNewWhatsit()
 {
  if (num_of_objects > ARRAY_SIZE(whatsit_cache))
   return 0;
  else 
   return whatsit_cache[num_of_objects++];  // post inc. on purpose 
 }
掩饰不了的爱 2024-12-01 21:52:45

您可以重载operator new,但重载的运算符不会返回对象。它返回对象的内存,并且实现安排调用构造函数。

所以你不能完全做你想做的事。

相反,如果您试图避免的成本是内存分配的成本,那么您的重载可以从预分配的块中分配一些内存。显然,您需要负责跟踪哪些内容是免费的,哪些不是,您面临的挑战是比 PS2 开发套件附带的分配器更高效地完成此任务。这可能并不太难 - 如果您只处理一个类,并且假设没有人从该类派生,那么分配的大小是固定的,那么您就有不公平的优势。

如果您试图避免的成本是调用构造函数,那么operator new 不会帮助您,但是您可以编写一种包装器:

struct FooWrapper {
    Foo *foo;
    FooWrapper(): foo(choose_a_pre_existing_foo()) { }
    ~FooWrapper() {
        foo->reset(); // clear up anything that shouldn't be kept
        return_to_the_pool_for_reuse(foo);
    }
  private:
    FooWrapper(const FooWrapper &);
    FooWrapper &operator=(const FooWrapper &);
};

Foo *choose_a_pre_existing_foo() {
    // possibly some kind of synchronization needed if list is global
    // and program is multi-threaded.
    if list_of_foos.empty() {
        return new Foo();
    } else {
        Foo *f = list_of_foos.back();
        list_of_foos.pop_back();
        return f;
    }
}

You can overload operator new, but that overloaded operator doesn't return an object. It returns the memory for an object, and the implementation arranges for the constructor to be called.

So you can't do quite what you want.

Instead, if the cost you're trying to avoid is that of memory allocation, then your overload can assign some memory from a pre-allocated block. Obviously you're then responsible for tracking what's free and what isn't, and your challenge is to do this more efficiently than the allocator that comes with the PS2 devkit. That might not be too hard - you have an unfair advantage if you're only dealing with one class, and assuming nobody derives from it, that the size of the allocations is fixed.

If the cost you're trying to avoid is that of calling the constructor, then operator new doesn't help you, but you could write a sort of wrapper:

struct FooWrapper {
    Foo *foo;
    FooWrapper(): foo(choose_a_pre_existing_foo()) { }
    ~FooWrapper() {
        foo->reset(); // clear up anything that shouldn't be kept
        return_to_the_pool_for_reuse(foo);
    }
  private:
    FooWrapper(const FooWrapper &);
    FooWrapper &operator=(const FooWrapper &);
};

Foo *choose_a_pre_existing_foo() {
    // possibly some kind of synchronization needed if list is global
    // and program is multi-threaded.
    if list_of_foos.empty() {
        return new Foo();
    } else {
        Foo *f = list_of_foos.back();
        list_of_foos.pop_back();
        return f;
    }
}
笑红尘 2024-12-01 21:52:45

重载 new充满危险的。它不仅仅是 C++ 的 malloc,它还具有对象生命周期和异常安全等重要语义。

当您调用 new 时,构造函数将被调用。您不想两次构造一个对象,因为您无法明智地销毁它两次。充其量你会泄漏资源。

您可能想要的不仅仅是一个单例,也许尝试这样的东西:

foo.h

struct Foo {
    static Foo instance_a;
    static Foo instance_b;
    enum Predefined {
        ALICE,
        BOB
    };
    static Foo & instance (Predefined);
    // ...
}

foo.cpp

Foo Foo :: instance_a (1, 2, 3);
Foo Foo :: instance_b ("alpha");

namespace {
    Foo alice;
    Foo bob (1, "x");
}

Foo & Foo :: instance (Predefined name) {
    // ...
    return alice;
}

大量的可能性。

Overloading new is fraught with peril. It's more than just C++'s malloc, it has important semantics for object lifetimes and exception safety and so on.

When you call new the constructor gets called. You don't want to construct an object twice because you can't sensibly destroy it twice. At best you will leak resources.

You might want more than a mere singleton, maybe try something like this:

foo.h

struct Foo {
    static Foo instance_a;
    static Foo instance_b;
    enum Predefined {
        ALICE,
        BOB
    };
    static Foo & instance (Predefined);
    // ...
}

foo.cpp

Foo Foo :: instance_a (1, 2, 3);
Foo Foo :: instance_b ("alpha");

namespace {
    Foo alice;
    Foo bob (1, "x");
}

Foo & Foo :: instance (Predefined name) {
    // ...
    return alice;
}

Loads of possibilities.

归属感 2024-12-01 21:52:45

如果您想要单个对象,可以使用 Singleton 模式
如果你想要多个对象,你需要一个 对象池

If you want a single object, the Singleton pattern can be used.
If you want multiple objects, you need an object pool.

凑诗 2024-12-01 21:52:45

您不仅不能修改 operator new 来执行您想要的操作(它只是一个分配函数),您也不应该这样做。颠覆新表达式的含义将使您的代码更难理解,没有任何好处

如果您想要全新的功能,那就编写代码!在这里,您需要的可能是一个类(我们不能告诉),或者可能只是一个函数:

template<typename T, typename... U>
std::shared_ptr<T> // for one std::shared_ptr seems appropriate
make(U&&... u);

然后客户端代码使用这个类似工厂的函数来获取它需要的对象。该函数实际上有什么作用?它是否使用享元模式缓存对象?它缓存内存而不是对象吗?客户端代码不关心并且不想。它所关心的只是获得它所要求的对象。

同时,函数中的代码会执行所需的操作。如果明天你意识到你错了,你可以更改里面的代码,希望它不会影响其余的。至少它还有战斗的机会。

Not only you can't modify operator new to do what you want (it's an allocation function only), you shouldn't. Subverting the meaning of a new expression would make your code harder to understand, for no benefits at all.

If you want brand new functionality, then write code! Here, what you need might be a class (we can't tell), or maybe just be a function:

template<typename T, typename... U>
std::shared_ptr<T> // for one std::shared_ptr seems appropriate
make(U&&... u);

The client code then uses this factory-like function to obtain the objects it needs. What does the function actually do? Does it cache objects using a Flyweight pattern? Does it cache memory instead of objects? The client code doesn't care and doesn't want to. All it cares is that it obtains the object it asks for.

Meanwhile, the code in the function does whatever it needs to. If tomorrow you realize you got it wrong, you can change the code inside and hopefully it won't affect the rest. At least it has a fighting chance to.

素手挽清风 2024-12-01 21:52:45

我建议使用桥接模式

这意味着您的客户可以像往常一样在一个简单的公共类上调用 new ,该公共类在内部选择构建或不构建什么。

所包含的类对于您的库来说可以是私有的。

I would suggest using the bridge pattern.

This means that your client can call new as normal on a trivial public class that internally makes the choice about what to construct or not construct.

The contained class can be private to your library.

药祭#氼 2024-12-01 21:52:45

使用operator::new的问题是,在调用new之后,编译器会自动生成一个操作码来调用构造函数,因此new本身不负责构造函数。
你想要的是一个单例:

struct Foo
{
    static Foo& NewObject()
    {
        static Foo* _foo = new Foo;
        return *_foo;
    }
}

或某种数组:

struct Foo
{
    static Foo& NewObject()
    {
        static Foo* _foo = new Foo[128];
        static int index = 0;

        if(index == 128)
            index = 0;
        return _foo[index++];
    }
}

The thing about using operator ::new is that the compiler will automatically generate an opcode to call the constructor after the call to new, so new itself isn't in charge of the constructor.
What you want is either a singleton:

struct Foo
{
    static Foo& NewObject()
    {
        static Foo* _foo = new Foo;
        return *_foo;
    }
}

or some kind of array:

struct Foo
{
    static Foo& NewObject()
    {
        static Foo* _foo = new Foo[128];
        static int index = 0;

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