如何在C++中重载运算符&?

3
如何在C++中重载运算符&?我尝试过以下代码:
#ifndef OBJECT_H
#define OBJECT_H
#include<cstdlib>
#include<iostream>

namespace TestNS{

    class Object{
    private:
        int ptrCount;
    public: 
        Object(): ptrCount(1){           
            std::cout << "Object created." << std::endl;
        }
        void *operator new(size_t size);
        void operator delete(void *p);
        Object *operator& (Object obj);
    };

    void *Object::operator new(size_t size){            
            std::cout << "Pointer created through the 'new' operator." << std::endl; 
            return malloc(size);
        }

    void Object::operator delete(void *p){
            Object * x = (Object *) p;
            if (!x->ptrCount){
                free(x);
                std::cout << "Object erased." << std::endl;
            }
            else{
                std::cout << "Object NOT erased. The " << x->ptrCount << "references are exist." 
                    << std::endl;
            }
        }
    
    Object *Object::operator& (Object obj){
            ++(obj.ptrCount);
            std::cout << "Counter is increased." << std::endl;
            return &obj;
        }
}
#endif

主要功能:
#include<iostream>
#include"Object.h"

namespace AB = TestNS;

int main(int argc, char **argv){
    AB::Object obj1;
    AB::Object *ptrObj3 = &obj1; // the operator& wasn't called.
    AB::Object *ptrObj4 = &obj1; // the operator& wasn't called.

    AB::Object *obj2ptr = new AB::Object();
}

输出结果:

对象已创建。

通过 'new' 运算符创建了指针。

对象已创建。

我的运算符&没有被调用。为什么?


4
尝试使用AB::Object *ptrObj5 = obj1 & obj1;,你就会明白为什么了。 - johnchen902
3
我认为你在做的事情是一个非常糟糕的想法。使用 operator& 来实现引用计数将会带来麻烦。 - Sebastian Redl
因为这是一个不完整的解决方案。特别是如果你从操作符返回一个原始指针。至少要返回一些东西,在销毁时减少引用计数。但是关于重载取地址运算符的问题在于它使得与对象一起工作变得很烦人。另外,对于指针而言,普通引用怎么办?我可以只说Object&或=*somePointer,你无法跟踪它。基本上,这个方案中有太多漏洞可以溜走,你会花费所有时间来调试引用计数错误。 - Sebastian Redl
@Sebastian Redl,有可靠的方法来防止内存泄漏吗? - Andrey Bushman
1
首先,重载一元运算符&通常不是一个好主意。如果必须这样做,则您的设计存在缺陷 - &应该基于侵入式引用计数(使用std::enable_shared_from_this或自定义解决方案)返回指向智能指针的this。不要重载操作符newdelete,因为这些重载不是为此目的而设计的 - 而是隐藏构造函数并提供static smart_ptr<Object> CreatePtr(Args&&... args)包装器。请注意,在自动存储中不存在垃圾回收对象,也不存在于另一个非垃圾回收的对象中,因此这种设计会导致性能下降。 - Yakk - Adam Nevraumont
显示剩余2条评论
2个回答

14

您目前正在重载二进制&运算符(即按位与)。要重载一元&运算符,您的函数不应该带有任何参数。它作用的对象是由this指向的。

Object *Object::operator& (){
    ++(this->ptrCount);
    std::cout << "Counter is increased." << std::endl;
    return this;
}

3
你可能需要同时提供一个const和非const版本。这是非const版本,你还需要一个返回const Object*的const版本。 - Sebastian Redl
@sftrabbit,@Sebastian Redl 谢谢! - Andrey Bushman
此外,请注意通常情况下重载operator&是一个不好的想法,并且您不能在标准容器中使用重载一元运算符&的类型... - David Rodríguez - dribeas

2
sftrabbit的回答在语法方面是正确的,但请注意,您使用newdelete的方式并不一致。 newdelete运算符适用于原始内存,而不是构造对象。
当您执行A* p = new A时...
  • 调用operator new...
  • 然后在返回的内存地址上调用对象A的构造函数...
  • 最后将地址转换为A*并赋给p
同样,当您执行delete p时...
  • 调用A的析构函数...
  • 将内存地址交给operator delete以返还给系统。
在这两种情况下,A对象实例的状态(其成员的值)未定义:
  • operator new中,无论您做什么,都将被随后的构造函数调用覆盖。如果构造函数没有初始化某些内容,则标准规定其值未定义(并且不能保证与您在new中设置的值相同)。
  • operator delete中,无论您做什么,都是在一个已经死亡的对象上操作(并且在其中找到的内容不能保证是“最后的活动状态”)。
无论如何,在调用delete时对象都会死亡。您不能在operator delete期间“从死亡中拯救它”(因为这是在销毁之后调用的)。它的目的是放置墓碑,而不是使尸体复活。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接