Is this a C ++ override valid?

Sorry for the main question, but I'm having trouble finding the right thing for google.

#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;
}

      

It looks like this is the right job, then calls the destructor on obj1, leaving x with the garbage size, not 4. If it really is, why do it?

+2


source to share


7 replies


If there is a class C that has a constructor that takes an int, is this code valid?

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

      

Assuming C has operator=(C)

(which it will default to) the code is valid. What happens is that in the first line obj1 is being built with 3 as a parameter to the constructor. Then in the second line, a temporary C object is built with 4 as a parameter and then operator=

called on obj1 with that temporary object as a parameter. After that, the temporary object will be destroyed.

If it obj1

's in an invalid state after being assigned (but not before), it's likely a C issue operator=

.



Update: If x really needs to be a pointer, you have three options:

  • Let the user decide, instead of the destructor, when the value of x should be deleted by defining a destroy method that the user should call explicitly. This will leak memory if the user doesn't.
  • Define operator=

    so that it creates a copy of the integer instead of a copy of the value. If, in your real code, you use a pointer to something larger than int, this can be too expensive.
  • Use reference counting to keep track of how many instances of C a pointer to the same object holds and deletes the object when it reaches 0.
+2


source


If C contains a pointer to something, you almost always need to implement operator =. In your case, this will be the signature



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


source


I don't know C ++ deep enough, subtle enough to explain the problem you are facing. However, I know that it is much easier to ensure that the class behaves as you expect if you follow the Rule of Three , which the code you posted is breaking. Basically, it states that if you define any of the following, you must define all three:

  • Destructor
  • Copy constructor
  • Assignment operator

Note also that the implementation of the assignment operation must correctly handle the case where an object is assigned to itself (so-called "self-determination"). The following should work correctly (untested):

#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;
}

      

+2


source


NEW: What happens is that your destructor has freed the memory allocated by the C (4) constructor. So the pointer you copied from C (4) is a dangling pointer, meaning it still points to the memory location of the freed memory

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;
}

      

+1


source


Be honest about pointer rights! auto_ptr is great for this. Also, when creating a local, don't do C obj1 = C(3)

that, which creates two instances of C and initializes the first with the second's copy constructor.

Enjoy 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;
}

      

+1


source


Basically you are trying to re-implement the smart pointer.
It is not trivial to get the right solution for all situations.

Check out the available smart pointers in the standard first.

Basic implementation (which will fail in certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:

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);
      }

  };

      

+1


source


When do you check the value obj1

? Is this after you left the area?

In your example obj1

, a stack object. This means that as soon as you leave the function in which it is defined, it is cleaned up (the destructor is called). Try to allocate an object on the heap:

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

0


source







All Articles