重载新运算符

时间:2011-07-19 14:57:30

标签: c++ operators overloading

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

如果可以的话,你怎么能在第一时间创建对象:D

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

当新操作符返回指向可用内存的指针时,我看不到这种情况。

new Foo;

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

};

8 个答案:

答案 0 :(得分:6)

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

无论如何,如果你没有得到 new 对象,该语法的重点是什么?

答案 1 :(得分:4)

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

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

或者甚至是这个

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

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

如果您向操作员提供新的操作,请不要忘记您还需要提供操作员删除。

我猜你正试图建立一个内存池,记得实际测量和不测量性能,因为它并不总是值得麻烦恕我直言。

修改 在你的问题和其他一些答案之间进行阅读,我的猜测是你真的想要单独重载new / delete和singleton模式。而是采用工厂模式方法。

您的所有代码都会调用

  

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 
 }

答案 2 :(得分:2)

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

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

相反,如果您试图避免的成本是内存分配的成本,那么您的重载可以从预先分配的块中分配一些内存。显然,你负责跟踪什么是免费的,什么不是,你的挑战是比PS2 devkit附带的分配器更有效地做到这一点。这可能不会太难 - 如果你只处理一个类而假设没有人从它那里得到,你就会有不公平的优势,分配的大小是固定的。

如果您要避免的成本是调用构造函数,那么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;
    }
}

答案 3 :(得分:1)

如果您想要单个对象,可以使用Singleton pattern。 如果您想要多个对象,则需要object pool

答案 4 :(得分:1)

重载newfraught with peril。它不仅仅是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;
}

很多可能性。

答案 5 :(得分:0)

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

如果你想要全新的功能,那就写代码吧!在这里,你需要的可能是一个类(我们无法分辨),或者只是一个函数:

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

然后,客户端代码使用此类工厂函数来获取所需的对象。 实际的功能是什么?它是否使用Flyweight模式缓存对象?它是否缓存内存而不是对象?客户端代码不关心,不想。所有它关心的是它获得它要求的对象。

同时,函数中的代码可以执行任何需要的操作。如果明天你意识到你弄错了,你可以改变里面的代码,希望它不会影响其余部分。至少它有一个战斗的机会。

答案 6 :(得分:0)

我建议使用bridge pattern

这意味着您的客户端可以在一个简单的公共类上正常调用new,该公共类在内部选择构造或不构造的内容。

包含的类可以是您库的私有。

答案 7 :(得分:0)

使用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++];
    }
}