C++ 指针和参考问题 \ifndef删除 #定义删除(var)删除var,var=NULL #恩迪夫 使用名称空间std; 类测试员{ 私人: Teste*Z; 公众: Teste(){ AnyNum=5; _Z=零; } ~Teste(){ 如果(_Z!=NULL) 删除(_Z); } Teste*Z(){ _Z=新的测试仪; 返回Z; } 无效Z(测试*值){ 值->AnyNum=100; *_Z=*值; } int AnyNum; }; int main(int argc,char*argv[]){ Teste*b=新的Teste,*a; a=b->Z(); 是的,有: #ifndef DELETE #define DELETE(var) delete var, var = NULL #endif using namespace std; class Teste { private: Teste *_Z; public: Teste(){ AnyNum = 5; _Z = NULL; } ~Teste(){ if (_Z != NULL) DELETE(_Z); } Teste *Z(){ _Z = new Teste; return _Z; } void Z(Teste *value){ value->AnyNum = 100; *_Z = *value; } int AnyNum; }; int main(int argc, char *argv[]){ Teste *b = new Teste, *a; a = b->Z(); cout << "a->AnyNum: " << a->AnyNum << "\n"; b->Z(new Teste); cout << "a->AnyNum: " << a->AnyNum << "\n"; //wdDELETE(a); DELETE(b); return 0; }

C++ 指针和参考问题 \ifndef删除 #定义删除(var)删除var,var=NULL #恩迪夫 使用名称空间std; 类测试员{ 私人: Teste*Z; 公众: Teste(){ AnyNum=5; _Z=零; } ~Teste(){ 如果(_Z!=NULL) 删除(_Z); } Teste*Z(){ _Z=新的测试仪; 返回Z; } 无效Z(测试*值){ 值->AnyNum=100; *_Z=*值; } int AnyNum; }; int main(int argc,char*argv[]){ Teste*b=新的Teste,*a; a=b->Z(); 是的,有: #ifndef DELETE #define DELETE(var) delete var, var = NULL #endif using namespace std; class Teste { private: Teste *_Z; public: Teste(){ AnyNum = 5; _Z = NULL; } ~Teste(){ if (_Z != NULL) DELETE(_Z); } Teste *Z(){ _Z = new Teste; return _Z; } void Z(Teste *value){ value->AnyNum = 100; *_Z = *value; } int AnyNum; }; int main(int argc, char *argv[]){ Teste *b = new Teste, *a; a = b->Z(); cout << "a->AnyNum: " << a->AnyNum << "\n"; b->Z(new Teste); cout << "a->AnyNum: " << a->AnyNum << "\n"; //wdDELETE(a); DELETE(b); return 0; },c++,memory,pointers,set,C++,Memory,Pointers,Set,编译器生成的赋值运算符不会生成深度副本,而是生成浅层副本。您需要做的是为Teste编写一个合适的赋值运算符(可能还有一个复制构造函数)。此外,您不必在删除指针之前检查指针是否为空: void Z(Teste *value) { value->AnyNum = 100; *_Z = *value; // you need assignment operator } 您还遇到了另一个问题:_Z不是您应该使用的标识符。一般来说,最好避免使用前导下划线,尤其是双下划线或下划线后跟大写

编译器生成的赋值运算符不会生成深度副本,而是生成浅层副本。您需要做的是为
Teste
编写一个合适的赋值运算符(可能还有一个复制构造函数)。此外,您不必在删除指针之前检查指针是否为空:

void Z(Teste *value)
{
   value->AnyNum = 100;
   *_Z = *value; // you need assignment operator
}

您还遇到了另一个问题:_Z不是您应该使用的标识符。一般来说,最好避免使用前导下划线,尤其是双下划线或下划线后跟大写字母是为实现保留的。

(我试图将其作为注释添加,但这会使代码出错。)

我还强烈建议不要使用

~Teste()
{
   // no need for checking. Nothing will happen if you delete a NULL pointer
   if (_Z != NULL)
     DELETE(_Z);
}
但实际上

#ifndef DELETE
  #define DELETE(var) delete var, var = NULL
#endif
无效Z(测试*值){ 值->AnyNum=100; *_Z=*值; }

创建内存泄漏

“newteste”永远不会被删除,相反,您所做的是分配一个新对象作为参数,然后使用*_Z=*值复制其中的任何内容,但调用后不会删除该对象

如果你要写

b->Z(new Teste);
那会更好


当然,大多数人都会使用boost::shared_ptr或类似的工具来避免删除,比如这一行有内存泄漏:

Test* param - new Teste;
b->Z(param)
delete param;
由于函数的定义:

b->Z(new Teste);
看起来没有参数的Z应该是一个getter,而有参数的Z应该是一个setter。我猜你的意思是:

void Z(Teste *value){
    value->AnyNum = 100;
    *_Z = *value;
}
(请注意第三行)也就是说,将指针“value”指定给指针“_Z”,而不是将所指向的值复制到Z所指向的值上。这样,第一个内存泄漏将得到解决,但代码仍会有一个,因为_Z可能持有指针。因此,您必须执行以下操作:

void Z(Teste *value){
    value->AnyNum = 100;
    _Z = value;
}
正如在另一篇评论中提到的,真正的解决方案是使用智能指针。这里有一种更现代的方法来处理相同的代码:

void Z(Teste *value){
    value->AnyNum = 100;
    delete _Z; // you don't have to check for null
    _Z = value;
}
使用名称空间std;
类测试员{
私人:
boost::共享的;
公众:
Teste():AnyNum(5),Z_2;(NULL)
{ }
boost::shared_ptr Z()
{
复位(新测试仪);
返回Z_;
}
void Z(boost::shared_ptr值)
{
值->AnyNum=100;
Z_u=值;
}
int AnyNum;
};
int main(int argc,char*argv[]){
boost::shared_ptr b=新测试,a;
a=b->Z();
真是一团糟!
整个程序很难阅读,因为首先要选择标识符名称:

using namespace std;

class Teste {
    private:
        boost::shared_ptr<Teste> Z_;

    public:
    Teste() : AnyNum(5), Z_(NULL)
    { }

    boost::shared_ptr<Teste> Z()
    {
        Z_.reset(new Teste);
        return Z_;
    }

    void Z(boost::shared_ptr<Teste> value)
    {
        value->AnyNum = 100;
        Z_ = value;
    }

    int AnyNum;
};

int main(int argc, char *argv[]){
    boost::shared_ptr<Teste> b = new Teste, a;

    a = b->Z();

    cout << "a->AnyNum: " << a->AnyNum << "\n";

    b->Z(boost::shared_ptr<Teste>(new Teste));

    cout << "a->AnyNum: " << a->AnyNum << "\n";

    return 0;
}
我觉得那很难看。 当使用类时,它似乎非常不必要。你可以在变量超出范围时使用它,但在析构函数中这是一种浪费时间的行为。我认为将代码封装在一些智能指针中会更容易:


好的,您在析构函数中删除了一个指针成员。 这意味着您获得了指针的所有权。这意味着四个ule适用(类似于三个规则,但适用于所有权规则)。这意味着您基本上需要编写四个方法,否则编译器生成的版本会弄乱您的代码。您应该编写的方法有:

class Teste
{
    private:
        Teste *_Z;

    public:
        Teste()
        ~Teste()    // Delete the _Z pointer.
        Teste *Z();
        void Z(Teste *value);
};
您的代码只有其中两个。您需要编写另外两个。 或者,您的对象不应拥有原始指针的所有权。即,使用智能指针


这是不允许的。 保留以下划线和国会大厦字母开头的标识符。 操作系统宏可能会弄乱代码。请停止使用下划线作为标识符的第一个字符


这是不需要的。简单的删除就可以了。 _Z超出范围,因为它在析构函数中,所以无需将其设置为NULL。 delete操作符可以很好地处理空指针

~Teste(){
    if (_Z != NULL)
            DELETE(_Z);
}

如果多次调用Z()会发生什么情况(PS将*放在Z的旁边而不是测试对象的旁边会使其难以读取)。 每次调用Z()时,成员变量_Z都会被赋予一个新值。但是旧值会发生什么变化呢?基本上,您是在泄漏它。还可以通过返回指向对象的指针来实现 在Teste内部,您正在给其他人滥用对象的机会(删除对象等)。这不好。此方法没有明确的所有权

Teste *Z(){
    _Z = new Teste;
    return _Z;
}

您正在将新构造的对象(包含指针)的内容复制到另一个动态创建的对象中! 如果没有首先分配_Z会发生什么情况。构造函数将其设置为NULL,因此不能保证它具有有效值。 您分配的任何对象也应该删除。但此处的值是动态分配的,传递到Z中,但从未释放。之所以不释放它,是因为指针是c OPId进入_Z,当其析构函数被销毁时_Z被删除


读起来真是好听。别懒了,把它写好。 这被认为是一种糟糕的风格,您永远不会通过任何代码审查

Teste *b = new Teste, *a;

为a获取ab对象。但谁在破坏对象a或b

a = b->Z();
在那之后,它变得太复杂了。

(不是一个真正的答案,但一条评论也不行)

你定义宏的方式容易出现微妙的错误(而且目前还没有人发现它),请考虑你的代码:

b->Z(new Teste);
预处理器通过后会发生什么:

if (_Z != NULL) // yes, this check is not needed, but that's not the point I'm trying to make
                DELETE(_Z);
如果您仍然无法看到它,让我将其正确缩进:

if (_Z != 0)
        delete _Z; _Z = 0;
考虑到这种特殊的if情况,这没什么大不了的,但它会随着其他任何东西爆炸,你会花费很多时间尝试去做
Teste *Z(){
    _Z = new Teste;
    return _Z;
}
Teste& Z()
{
    delete _Z;       // Destroy the old value
    _Z = new Teste;  // Allocate a new value.
    return *_Z;      // Return a reference. This indicates you are retaining ownership.
                     // Thus any user is not allowed to delete it.
                     // Also you should note in the docs that it is only valid
                     // until the next not const call on the object
}
void Z(Teste *value){
    value->AnyNum = 100;
    *_Z = *value;
}
Teste *b = new Teste, *a;
Teste* b = new Teste;
Teste* a; // Why not set it to NULL
a = b->Z();
b->Z(new Teste);
if (_Z != NULL) // yes, this check is not needed, but that's not the point I'm trying to make
                DELETE(_Z);
if (_Z != 0)
        delete _Z; _Z = 0;
if (_Z != 0)
        delete _Z;
_Z = 0;