2 Replies Latest reply: Jul 22, 2011 5:21 AM by 877216 RSS

    Constructor calls in initialization lists

    877216
      Hello!

      I've encountered a difference in behavior between Solaris Studio 12 update 1 (CC: Sun C++ 5.10) and g++ that has me baffled.

      This is seen when a class's constructor features an initialization list before the start of its body. It seems that when I use a constructor call to initialize a member variable in the list, Solaris Studio calls that constructor once for the temporary object that is between parentheses and a second time to initialize my class's member variable with a copy constructor using the former temporary object. g++ by contrast calls that constructor only once.

      Here's a testcase that should hopefully clarify my point. The initialization list is in class Foo's constructor:

      File: "foo.h"
      #include <iostream>
      #include <stdlib.h>
      #include <string.h>
      
      class Bar {
           size_t length;
      public:
           Bar(){
                std::cout << "Bar no args constructor. This: " << this << std::endl;
           }
      
           Bar(size_t length){
                std::cout << "Bar length constructor. This: " << this << std::endl;
           }
      
      
           Bar( const Bar& ) {
                std::cout << "Bar copy constructor. This: " << this << std::endl;
           }
      
           virtual ~Bar(){
                std::cout << "Bar destructor. This:" << this << "\n";
           }
      
      
      };
      
      class Foo {
      private:
           int alpha;
           Bar bravo;
      public:
           Foo(int length);
      };
      File: "foo.cpp"
      #include "foo.h"
      
      Foo::Foo(int len): bravo(Bar(len)) {
           alpha=len;
      }
      File: "testcase.cpp"
      #include "foo.h"
      #include <unistd.h>
      
      int main( int argc, char** argv) {
           Foo testcase(4);
      
           usleep(2000000);
           std::cout << "Program end of life" << std::endl;
           return EXIT_SUCCESS;
      }
      When I compile these files with Solaris Studio...
      $ CC -library=Crun,Cstd  -o ./foo.o -c ./foo.cpp ; CC -library=Crun,Cstd -o ./sol_studio_testcase ./testcase.cpp ./foo.o
      ...the testcase program produces this output:
      $ ./sol_studio_testcase 
      Bar length constructor. This: 8047744
      Bar copy constructor. This: 804777c
      Bar destructor. This:8047744
      Program end of life
      Bar destructor. This:804777c
      By contrast, when I use g++...
      g++ -o ./gfoo.o -c ./foo.cpp; g++ -o ./gplusplus_testcase ./testcase.cpp ./gfoo.o
      ...the output shows only one call to a contructor for class Bar:
      Bar length constructor. This: 0x8047784
      Program end of life
      Bar destructor. This:0x8047784
      I'm working on a fairly large g++ codebase that makes heavy use of initialization lists throughout and relies on g++'s behavior in this regard (there's some vital memory management baked in the constructors and destructors).

      So would anyone here know if/how I could induce Solaris Studio's CC to behave like g++ in this case?

      Best regards,

      - Matt Boyer
        • 1. Re: Constructor calls in initialization lists
          Steve.Clamage-Oracle
          In the initialization
           Foo::Foo(int len): bravo(Bar(len)) { ... } 
          the program semantics call for creating an anonymous temp object of type Bar that is used to initialize the bravo member of Foo, and later destroyed.

          The C++ standard allows, but does not require, an implementation to eliminate the temp object in some circumstances. The Sun/Oracle C++ compiler does not currently have this optimization.

          But there is no reason in this case to write bravo(Bar(len))+, because bravo is already of type Bar. If you write the simpler code bravo(len)+, no temp object is implied or created by the compiler.
          • 2. Re: Constructor calls in initialization lists
            877216
            Hi Steve,

            Thanks for the reply. I was hoping for some combination of optimization options that would save me the work, but I guess I'll have to refactor that code and take out the constructors in the initialization list.

            Best regards,

            - Matt Boyer