此C ++重新分配是否有效?

时间:2009-10-04 23:13:13

标签: c++ oop

对不起基本问题,但我无法找到正确的谷歌。

#include <iostream>
#include <string>
using namespace std;

class C {
public: 
C(int n) {
    x = new int(n);
}

~C( ) {
    delete x;
}

int getX() {return *x;}

private: 
    int* x; 
}; 

void main( )  {
    C obj1 = C(3);
    obj1 = C(4);
    cout << obj1.getX() << endl;
}

看起来它正确地进行了赋值,然后在obj1上调用析构函数,使x保留垃圾值而不是值4.如果这是有效的,为什么要这样做?

7 个答案:

答案 0 :(得分:2)

  

如果有一个C类的构造函数接受一个int,那么这段代码是否有效?

C obj1(3);
obj1=C(4);

假设C有operator=(C)(默认情况下),代码有效。会发生的是,在第一行中,obj1构造为3作为构造函数的参数。然后在第二行,构造一个临时C对象,其中4作为参数,然后在obj1上调用operator=,并将该临时对象作为参数。之后,临时对象将被破坏。

如果obj1在分配后处于无效状态(但之前没有),则可能是C operator=出现问题。

更新:如果x确实需要成为指针,则有三个选项:

  1. 让用户而不是析构函数决定何时应该通过定义用户需要显式调用的销毁方法来删除x的值。如果用户忘记这样做,这将导致内存泄漏。
  2. 定义operator=,以便它将创建整数的副本而不是值的副本。如果在实际代码中使用指向比int大得多的东西的指针,这可能太贵了。
  3. 使用引用计数来跟踪C持有指向同一对象的指针的实例数,并在其计数达到0时删除该对象。

答案 1 :(得分:2)

如果C包含指向某个东西的指针,那么你几乎总是需要实现operator =。在你的情况下,它将有这个签名

class C
{    
    public:
    void operator=(const C& rhs)
    {
        // For each member in rhs, copy it to ourselves
    } 
    // Your other member variables and methods go here...
};

答案 2 :(得分:2)

我不太了解深度,微妙的C ++来解释你遇到的问题。但是,我知道,如果您遵循您发布的代码违反的Rule of Three,确保课程的行为方式要容易得多。基本上,它声明如果你定义以下任何一个,你应该定义所有三个:

  • 析构
  • 复制构造函数
  • 作业运算符

还要注意,赋值运算符实现需要正确处理将对象分配给自身的情况(所谓的“自我赋值”)。以下应该正常工作(未经测试):

#include <iostream>
#include <string>
using namespace std;

class C {
public: 
C(int n) {
    x = new int(n);
}

C(const C &other): C(other.getX()) { }

~C( ) {
    delete x;
}

void operator=(const C &other) {
    // Just assign over x.  You could reallocate if you first test
    // that x != other.x (the pointers, not contents).  The test is
    // needed to make sure the code is self-assignment-safe.
    *x = *(other.x);
}

int getX() {return *x;}

private: 
    int* x; 
}; 

void main( )  {
    C obj1 = C(3);
    obj1 = C(4);
    cout << obj1.getX() << endl;
}

答案 3 :(得分:1)

发生的事情是你的析构函数已经释放了由C(4)的构造函数分配的内存。所以你从C(4)复制的指针是一个悬空指针,即它仍然指向解除分配的内存的内存位置

class C {
public: 
C(int n) {
    x = new int(n);
}

~C( ) {
    //delete x; //Don't deallocate
}

void DeallocateX()
{
 delete x;
}

int getX() {return *x;}

private: 
    int* x; 
}; 

int main(int argc, char* argv[])
{
    // Init with C(3)
    C obj1 = C(3);
    // Deallocate C(3)
    obj1.DeallocateX();
    // Allocate memory and store 4 with C(4) and pass the pointer over to obj1
    obj1 = C(4);
    // Use the value
    cout << obj1.getX() << endl;
    // Cleanup
 obj1.DeallocateX();


 return 0;
}

答案 4 :(得分:1)

明确指针的所有权! auto_ptr非常适合这个。此外,在创建本地时,不要创建C obj1 = C(3)创建C的两个实例,并使用第二个的复制构造函数初始化第一个。

Heed The Guru.

class C {
public:
   C(int n) : x(new int(n)) { }
   int getX(){ return *x; }
   C(const C& other) : x(new int(*other.x)){}
   C& operator=(const C& other) { *x = *other.x; return *this; }
private:
   std::auto_ptr<int> x;
};

int main() {
   C obj1(3);
   obj1 = C(4);
   std::cout << obj1.getX() << std::endl;
}

答案 5 :(得分:1)

基本上你正试图重新实现一个智能指针 这对于所有情况都是正确的并非易事。

请先查看标准中的可用智能指针。

基本实现(在某些情况下会失败(复制其中一个标准版本以获得更好的一个))。但这应该涵盖基础知识:

class X
{
    int*     data;

    public:
      // Destructor obvious
      ~X()
      {
          delete data;
      }
      // Easy constructor.
      X(int x)
          :data(new int(x))
      {}
      // Copy constructor.
      // Relatively obvious just do the same as the normal construcor.
      // Get the value from the rhs (copy). Note A class is a friend of
      // itself and thus you can access the private members of copy without
      // having to use any accessor functions like getX()
      X(X const& copy)
          :data(new int(copy.x))
      {}
      // Assignment operator
      // This is an example of the copy and swap idiom. This is probably overkill
      // for this trivial example but provided here to show how it is used.
      X& operator=(X const& copy)
      {
          X tmp(copy);
          this->swap(tmp);
          return this;
      }
      // Write a swap() operator.
      // Mark it is as no-throw.
      void swap(X& rhs) throws()
      {
          std::swap(data,rhs.data);
      }

  };

答案 6 :(得分:0)

您何时测试obj1的值?是在你离开范围之后吗?

在您的示例中,obj1是一个堆栈对象。这意味着只要您离开它定义的函数,它就会被清理(析构函数被调用)。尝试在堆上分配对象:

C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);