Re: [ROOT] Seg.Violation on return TGraph

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Wed Mar 12 2003 - 22:06:21 MET


Hi Rene, 


Rene Brun <Rene.Brun@cern.ch> wrote concerning
  Re: [ROOT] Seg.Violation on return TGraph [Wed, 12 Mar 2003 19:57:35 +0100 (MET)] 
----------------------------------------------------------------------
> Hi Sven,
> 
> What you do is illegal in C++ 

Erh, no it's not illegal (that would make the function 
`int foo(int x) { int y = x; return y;}' illegal too :-) ... 

> (and anyhow very inefficient).

... but highly inefficient - yes. 

> When leaving your makegraph function, the object is deleted.  
> when leaving the scope !

No it isn't - it's copied out (via the copy constructor) before being
deallocated from the stack, passing the copy on the return stack!  Not
very cool, but not illegal at all. 
 
> You can do as shown below

The example you gave is much more efficient of course, but try also
this piece of code: 

  #include <iostream>
  
  class foo {
  private:
    int _foo;
  public:
    foo(int f) : _foo(f) { 
      std::cout << "- " << _foo << ": foo::foo(int)" << std::endl; }
    ~foo() { 
      std::cout << "- " << _foo << ": foo::~foo" << std::endl; }
    foo(const foo& o) : _foo(o._foo) { 
      std::cout << "- " << _foo << ": foo::foo(const foo&)" << std::endl; }
  };
  
  foo create_foo1(int x) {
    std::cout << "+ 1: plain object" << std::endl;
    foo f(x);
    return f;
  }
  
  foo& create_foo2(int x) {
    std::cout << "+ 2: reference" << std::endl;
    foo f(x);
    return f;
  }
  
  foo* create_foo3(int x) {
    std::cout << "+ 3: pointer" << std::endl;
    foo* f  = new foo(x);
    return f;
  }
  
  foo create_foo4(int x) {
    std::cout << "+ 4: direct object" << std::endl;
    return foo(x);
  }
  
  int main(int argc, char** argv) {
    foo  f1 = create_foo1(1);
    std::cout << "==> Notice the extra copy above?" << std::endl;
  
    foo& f2 = create_foo2(2);
    std::cout << "==> Notice the destruction but no copy above?" << std::endl;
  
    foo* f3 = create_foo3(3);
    std::cout << "==> Notice there's no copy/deletion at all?" << std::endl;
  	
    foo  f4 = create_foo4(4);
    std::cout << "==> Notice the lack of copy here too?" << std::endl;
  
    std::cout << "==> At end of program 1 & 4 is free'd - 2 is not" << std::endl;	
    return 0;
  }

In particular notice the 3rd case, were the function construct the
object on the return stack, rather than as a temporary.  I haven't
checked with the ISO/IEC standard whether this the correct _and_
guarantied behaviour, but it compiles and works the same with both GCC
3.0.4, Intel's C++ compiler version 7.0, Compaq C++ v6.3, and Sun
WorkShop 4.2 so I'd say there's a pretty good chance it's right.  Now,
whether other compilers (and linkers) behave the same - I really have
no idea (my guess is at least one will behave differently, even if the
behaviour is dictated by the ISO/IEC standard - guess which one :-)

I'd like to direct your attention to Andrei Alexandrescu excellent
article [1] on how to avoid temporary objects.  Also his book is quite
good too. 

Yours, 

 ___  |  Christian Holm Christensen 
  |_| |	 -------------------------------------------------------------
    | |	 Address: Sankt Hansgade 23, 1. th.  Phone:  (+45) 35 35 96 91
     _|	          DK-2200 Copenhagen N       Cell:   (+45) 24 61 85 91
    _|	          Denmark                    Office: (+45) 353  25 305
 ____|	 Email:   cholm@nbi.dk               Web:    www.nbi.dk/~cholm
 | |

[1] http://www.cuj.com/experts/2102/alexandr.htm?topic=experts  



This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:10 MET