How does a destructor know when to activate itself? What can you rely on?

Say, for example, I have the following code (pure example):

class a {
   int * p;
public:
   a() {
      p = new int;
   }
   ~a() {
      delete p;
   }
};

a * returnnew() {
   a retval;
   return(&retval);
}

int main() {
   a * foo = returnnew();
   return 0;
}

In returnnew (), would retval be destroyed after the function returns (when retval is out of scope)? Or it will disable auto kill after I return the address and I could say delete foo; at the end of main ()? Or in a similar vein (pseudo-code):

void foo(void* arg) {
   bar = (a*)arg;
   //do stuff
   exit_thread();
}

int main() {
   while(true) {
      a asdf;
      create_thread(foo, (void*)&asdf);
   }
   return 0;
}

where will the destructor go? where should i say delete? or is this behavior undefined? Would it be the only possible solution to use counted STLs? How will this be implemented?

Thank you, I used C ++ for a while, but have not been in this situation and do not want to create memory leaks.

+3
6

, .

, , delete.

, . - , .

, :

a * returnnew() 
{
   a retval;
   return(&retval);
}

a destructor , , returnnew(). , , .

?

delete new
delete[], new[]

undefined?

, , undefined. , .

STL- ?

. .

?

//Shows how to fill an object value by reference
void fillA(a& mya) 
{
   mya.var = 3;
}

//Shows how to return a value on the heap
a* returnNewA() 
{
  //Caller is responsible for deleting the returned pointer.
  return new a();
}

//Shows how to return by value, memory should not be freed, copy will be returned
a returnA() 
{
  return a();
}
+10
a * returnnew() {
   a retval;
   return(&retval);
}

retval , , , . , , .

, , .

a* returnnew() 
{ 
   a* retval = new a();  
   return retval;  
}

a. , delete, .

a , , . , .

class a 
{
   int * p;
public:
   a(a const& rhs) 
   {
      p = new int(rhs.p)
   }
   a() 
   {
      p = new int;
   }
   ~a() 
   {
      delete p;
   }
};

a a. , a , :

a returnnew() 
{ 
   a retval;  
   return retval; 
}

retval , , , . .

, , . , .

++ - , , . , , .

+1

, ++ - .

-, (, boost scoped_ptr shared_ptr). , , , . , delete , .

+1

returnnew() , . retval, , :

a * returnnew() {
    a * retval = new a;
    return retval;
}

:

a * returnnew() {
    return new a;
}

, , , , delete/delete []/free, ( , ), , " " //etc-.

, , , (), . , , , , .

0

+1 , Threading.

asdf, , asdf . asdf . asdf . , . , asdf , , , asdf - ITS, .

void foo(void* arg) { 
   bar = (a*)arg; // child has reference to a parent stack address!
   //do stuff 
   exit_thread(); 
} 

int main() { 
   while(true) { 
      a asdf; // parent stack
      create_thread(foo, (void*)&asdf); // parent and child diverge here, asdf auto-destroyed
   } 
   return 0; 
} 
0

:

void foo(void* arg) {
   bar = (a*)arg;
   //do stuff
   exit_thread();
}

int main() {
   while(true) {
      a asdf;
      create_thread(foo, (void*)&asdf);
   }
   return 0;
}

The destructor is called in the closing bracket of the while loop. This means that it will be called each iteration of the loop (and it will be built again for the next iteration).

As a useful tool for exploring the nuances of designers and destructors and applications, consider the following class to help you answer these questions yourself in the future:

class trace {
private:
  std::string msg_;
public:
  explicit trace(const std::string &msg) : msg_(msg) {
    std::cerr << "Constructing: " << msg_ << std::endl;
  }
  ~trace() {
    std::cerr << "Destructing: " << msg_ << std::endl;
  }
};

Use it this way:

trace glb("global");

main() {
  trace t1("top of main");

  for(int i = 0; i < 10; ++i)
  {
    trace t2("inside for");
  }

  return 0;
}

The results may surprise you.

0
source

Source: https://habr.com/ru/post/1740248/


All Articles