Loading ...
Sorry, an error occurred while loading the content.

Re: [XP] C++ stack objects [OT?] (was: Continous integration without version control)

Expand Messages
  • Phlip
    ... He means polymorphic construction. The following two statements bind the type at compile time: Thing a; Thing *b (new Thing); This is the only way to get
    Message 1 of 2 , Sep 1, 2001
    • 0 Attachment
      kevinxp@... wrote:
      >
      > --- In extremeprogramming@y..., "C. Keith Ray" <ckeithray@h...> wrote:
      > > And then a Duh! Moment when I realized that maybe Mock objects COULD have
      > > been useful... but only just barely, this is C++ and using Mock objects
      > > would have required not using stack-based objects (no polymorphism for
      > > stack-based objects), so I'd need a factory object and a some kind of smart
      > > pointer template class, which can be a lot harder to write than you might
      > > think. [I really regret the popularization of C++.]
      >
      > This might be better offline, but I don't understand what you mean by "no
      > polymorphism for stack-based objects". An object is an object, whether it
      > was created on the stack (local), in data space (global), or on the heap
      > (using new). If the class has polymorphism, any object of that class will
      > as well.

      He means polymorphic construction. The following two statements bind the
      type at compile time:

      Thing a;
      Thing *b (new Thing);

      This is the only way to get something and only bind to its type at
      runtime:

      Thing *c (ThingFactory.newThing(data));

      --
      Phlip
    • C. Keith Ray
      ... quick lesson on slicing -- the bane of C++ stack-based objects: class A { public: virtual void foo(); int myAa; }; class B { public: virtual void foo();
      Message 2 of 2 , Sep 1, 2001
      • 0 Attachment
        > --- In extremeprogramming@y..., "C. Keith Ray" <ckeithray@h...> wrote:
        >> And then a Duh! Moment when I realized that maybe Mock objects COULD have
        >> been useful... but only just barely, this is C++ and using Mock objects
        >> would have required not using stack-based objects (no polymorphism for
        >> stack-based objects), so I'd need a factory object and a some kind of smart
        >> pointer template class, which can be a lot harder to write than you might
        >> think. [I really regret the popularization of C++.]
        >
        > This might be better offline, but I don't understand what you mean by "no
        > polymorphism for stack-based objects". An object is an object, whether it
        > was created on the stack (local), in data space (global), or on the heap
        > (using new). If the class has polymorphism, any object of that class will
        > as well.

        quick lesson on "slicing" -- the bane of C++ stack-based objects:

        class A
        {
        public:
        virtual void foo();
        int myAa;
        };

        class B
        {
        public:
        virtual void foo(); //override parent method
        int myBa;
        }

        stack-allocated objects ('by value' instead of 'pointer' or 'reference'):

        A a; a.foo(); // calls A::foo. 'a' uses 8 bytes of stack memory.
        B b; b.foo(); // calls B::foo 'b' uses 12 bytes of stack memory.

        a = b;
        a.foo(); // calls A::foo. 'a' still has only 8 bytes of stack memory.

        Assigning 'b' to 'a' does NOT make 'a' refer to a 'B' object. Instead, 'a'
        still refers to an 'A' object. The assignment not only slices off the member
        variable 'myBa', but it also slices off the virtual function table pointer
        that pointed to the overridden method 'B::foo()'.

        Thus: you can only use concrete classes as stack-based objects (variables
        declared "by value" inside a function). To use a mock object that has the
        same abstract base class as the production class, I would have to use a
        pointer or a smart-pointer, referring to a heap-allocated object.

        The reason I am using a stack-based objects, is because C++ guarantees that
        the object's destructor will be called when its variable goes out of scope
        -- even if an exception is thrown. Since standard C++ does not have
        "try...finally" syntax, the destructors of stack-allocated objects are used
        to make sure clean-up is performed in the presence of exceptions.

        This 'slicing problem' is unique to C++ as far as I know. It comes from
        attempting to make a C++ 'class' equivalent to a C 'struct' (in various
        circumstances...blah blah.)

        If Objective-C had been freely given away like CFront was, maybe we would
        not be having this conversation, since Objective-C creates all objects on
        the heap (no matter where the variable is declared), just like every other
        OO language except C++.

        There is a solution, but it requires pointers...

        class AWrapper
        {
        public:
        A* myAValue;
        ~AWrapper()
        {
        delete myAValue;
        }
        };

        // 'new' allocates objects in the heap instead of the stack.
        AWrapper a; a.myAValue = new A; a.myAValue->foo(); // calls A::foo
        AWrapper b; b.myAValue = new B; a.myAValue->foo(); // calls B::foo

        a = b; // memory leak! (no garbage collection in std C++)
        a.myAValue->foo(); // calls B::foo

        To prevent the memory leak, one needs to define "operator=" to delete the
        current object's pointer IF the assignment is not from self to self
        (ie. "a = a").

        To avoid accessing the pointer member variable directly for calling virtual
        functions from outside AWrapper, one can define "operator->". which is a bit
        of C++ trickery that I don't want to get into here.

        There is a bug in this example code -- the B object gets deleted twice,
        because it is referred to by 'a' and 'b'. This usually causes a nice crash,
        so you need your wrapper class to keep count of how many AWrapper variables
        are referring to the same object. This complicates the implementation of
        "operator=", the destructor, constructor, and copy-constructor, and so on.

        This is why sometimes the question "can you do XP with C++?" sometimes comes
        up. The language requires about 10 times more effort than Smalltalk, and at
        least twice as much effort as Java, and requires a lot of care to enable
        using Mock objects, for example.

        I recently found the "Boost" C++ library at <http://www.boost.org>, which
        provides a template class for smart pointers. If I had found that site 18
        days ago, I could have used smart pointers, a factory object, and mock
        objects for my test-first programming.
      Your message has been successfully submitted and would be delivered to recipients shortly.