Article Discussion
The Law of The Big Two
Summary: Welcome to the first installment of Smart Pointers, a monthly- ish column written exclusively for The C++ Source. Here, two seasoned [1] programmers—Bjorn Karlsson and Matthew Wilson—carefully dissect C++ idioms, tricks, and power techniques. To make up for the fact that these are very serious topics, we shall occasionally expose you to really crummy programming jokes, too. Now, who said there was no such thing as a free lunch? In this instalment the authors update The Law of The Big Three, and explain which of the three magic member functions is often not needed.
36 posts.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: May 9, 2008 9:32 AM by m
    Chuck
     
    Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
    The Law of The Big Two
    October 1, 2004 8:00 AM      
    In this inaugural installment of their new column, Matthew Wilson and Bjorn Karlsson update the well-known Law of The Big Three, explaining which one of those member functions is not always needed.

    www.artima.com/cppsource/bigtwo.html
    • Vesa
       
      Posts: 5 / Nickname: vkarvone / Registered: June 14, 2004 5:19 AM
      Re: The Rule of The Big Two
      October 3, 2004 1:39 PM      
      After a diligent rereading of the article, I had to grab the keyboard again. The below code taken from the article is extremely error-prone:

      template <typename T> class RAII {
      // ...
      operator T*() {
      return p_;
      }

      operator const T*() const {
      return p_;
      }
      // ...
      };


      It is just too easy to accidentally return (or pass as an argument) a dangling pointer from (to) a function when the conversion from a smart pointer to a plain pointer is implicit. I'm very disappointed that the authors, who really should know better, do not mention this in the article. Having debugged bugs caused by conversion operators like above, I can only advice everyone to never provide such dangerous implicit conversions.
      • Matthew
         
        Posts: 20 / Nickname: bigboy / Registered: June 14, 2004 10:43 AM
        Re: The Rule of The Big Two
        October 3, 2004 3:27 PM      
        [This is a reply to the "extremely error-prone" issue.]

        I think you've, perhaps reasonably, mistaken the intent of the RAII class. As stated in the text, it is "intended mainly for the purpose of adding RAII to simple classes".

        I concede, in hindsight, that that should be better expressed, i.e., something along the lines of "implicit conversions are dangerous (which I assure you we do know <g>), and should not be used in smart pointer classes in general. There are much better alternatives for generalised treatment of raw and smart pointers, which we intend to deal with in a future instalment. RAII does have them, however, because it is solely intended for use inside other classes, and to be a plug in replacement for raw pointers in that context."

        Alternatively, we could just have dropped the implicit conversions, which would barely have troubled our use of the class, and saved you consternation and our readers any confusion.

        In hindsight, the latter approach is probably the better one. I'll get together with Bjorn, and we'll look into adjusting the article accordingly.

        Thanks for the keen eye, and the willing fingers. :-)
        • Vesa
           
          Posts: 5 / Nickname: vkarvone / Registered: June 14, 2004 5:19 AM
          Re: The Rule of The Big Two
          October 3, 2004 11:12 PM      
          > I think you've, perhaps reasonably, mistaken the intent of
          > the RAII class. As stated in the text, it is "intended
          > mainly for the purpose of adding RAII to simple
          > classes
          ".

          I did read that line and I understood the intention of the class on the first reading. (That's why I emphasized being diligent.) However, being an exercise tutor on a C++ course and recommending innocent students to read this (otherwise excellent!) article, I simply can't let things like this slip through without critique.

          > Alternatively, we could just have dropped the implicit
          > conversions, which would barely have troubled our use of
          > the class, and saved you consternation and our readers any
          > confusion.

          Yes. I think that would have been the better choice. It just doesn't take a lot of effort (or a lot of lines) to provide a few more operators. Those few lines would very likely save someone from a debugging/fixing nightmare.
          • Bjorn
             
            Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
            Re: The Rule of The Big Two
            October 3, 2004 11:18 PM      
            Hello Vesa,

            > I did read that line and I understood the intention of the
            > class on the first reading. (That's why I emphasized being
            > diligent.) However, being an exercise tutor on a
            > C++ course and recommending innocent students to read this
            > (otherwise excellent!) article, I simply can't let things
            > like this slip through without critique.

            You are absolutely right (and diligent!).

            > Yes. I think that would have been the better choice. It
            > just doesn't take a lot of effort (or a lot of lines) to
            > provide a few more operators. Those few lines would very
            > likely save someone from a debugging/fixing nightmare.

            I'll update the article during the day. Thanks!

            Bjorn
    • Colin
       
      Posts: 1 / Nickname: craffert / Registered: October 1, 2004 9:12 AM
      Final version of constructor not exception-safe.
      October 1, 2004 1:23 PM      
      The problem is that we cannot depend on the order of initialization. Here is the final version of the constructor from the article:

      Example() :
      p_(new SomeResource()),
      p2_(new SomeResource()) {}

      The second call to new can occur before p_ is initialized with the result of the first call to new. If the second call throws an exception, the result of the first call will be leaked.

      The only way to be certain that this code is exception-safe is the unfortunate method of initializing the members inside the constructor.

      Example()
      {
      p_.reset(new SomeResource());
      p2_.reset(new SomeResource();
      }
      • indranil
         
        Posts: 4 / Nickname: indranilb / Registered: February 25, 2004 11:41 PM
        Re: Final version of constructor not exception-safe.
        October 2, 2004 0:54 AM      
        It is safe. The commas in the member initialisation list are sequence points. Therefore in the example the first SomeResource will be allocated, constructed and assigned to p_ before the second SomeResource begins construction.

        This only works in constructor member initialisation lists. You're right that for function calls this would not be exception safe.

        foo(RAII(new X()), RAII(new X());

        The above code would not be safe because, as you pointed out, the two X objects could be created before either is assigned to the RAII wrappers. So if the first new X() succeeded and the second new X() threw, then the RAII would not clean up the first X.
        • Steve
           
          Posts: 8 / Nickname: essennell / Registered: September 7, 2004 10:19 PM
          Re: Final version of constructor not exception-safe.
          October 4, 2004 2:28 AM      
          > It is safe. The commas in the member initialisation list
          > are sequence points. Therefore in the example the first
          > SomeResource will be allocated, constructed and assigned
          > to p_ before the second SomeResource begins construction.
          >

          No, the commas are *not* sequence points. The order of initialization is defined in the data-member list for the class. E.g.

          struct T
          {
          T() : p( new X ), q( new X ) { }

          X * q;
          X * p;
          };

          q is *always* initialized before p.

          In the article, the order of the members matched the order in the initializer list, so all is fine - and no confusion to anyone.
    • Daniel
       
      Posts: 5 / Nickname: teske / Registered: October 3, 2004 4:54 PM
      Re: The Rule of The Big Two
      October 3, 2004 10:02 PM      
      >Example(const Example& other)
      > : p_(new SomeResource(other.p_ ? *other.p_ : 0)),
      > p2_(new SomeResource(other.p2_ ? *other.p2_ : 0)) {}

      Isn't that supposed to be:
      Example(const Example& other)
      : p_(other.p_.get()? new SomeResource( *other.p_) : 0),
      p2_(other.p2_.get()? new SomeResource( *other.p2_): 0)
      • Bjorn
         
        Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
        Re: The Rule of The Big Two
        October 4, 2004 0:03 AM      
        Hello Daniel,

        > Isn't that supposed to be:
        > Example(const Example& other)
        > : p_(other.p_.get()? new SomeResource( *other.p_) :
        > p_) : 0),
        > p2_(other.p2_.get()? new SomeResource( *other.p2_):
        > r.p2_): 0)

        No, the original RAII class had an implicit conversion to T*, so there was no (need for) get(). However, the constructor of the Example class always allocates (and only deallocates in the destructor) p_ and p2_, so the code should be:

        Example(const Example& other) :
        p_(new SomeResource(*other.p_)),
        p2_(new SomeResource(*other.p2_)) {}

        Cheers,
        Bjorn
        • Daniel
           
          Posts: 5 / Nickname: teske / Registered: October 3, 2004 4:54 PM
          Re: Example(const Example& other)
          October 4, 2004 1:08 AM      
          Sorry, the .get() is there because I tested the example with a const auto_ptr<>.
          But I still think there is an error in the code.
          Using excessive formating and ignoring p2_:
          Article:

          p_(new SomeResource(
          other.p_ ?
          *other.p_ :
          0))


          My:

          p_(
          other.p_?
          new SomeRessource(*other.p_):
          0)


          Because if other.p_ == 0 then the version in the article will call new SomeRessource(0), which normally doesn't compile.

          You are right that other.p_ can't be 0.
          • Bjorn
             
            Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
            Re: Example(const Example& other)
            October 4, 2004 3:03 AM      
            [snip]
            > But I still think there is an error in the code.

            Yes, you're right (the code didn't match the one I have locally). The error goes away when the test is omitted.

            Thanks,
            Bjorn
    • Uwe
       
      Posts: 4 / Nickname: uwe / Registered: August 27, 2003 8:00 PM
      Re: The Rule of The Big Two
      October 4, 2004 0:28 AM      
      Why stop here?

      Why not make it "The Rule of The Big Zero"?

      When the object is copied, you will either want to have reference counting or deep copy semantic for its owned resources.

      If you opt for reference semantics, a suitable smart pointer can just do it.

      To enable deep copy semantic, the smart pointer would need to accept some copy mechanism function (object) pointer. You would either use a creation function rsp. a factory function if a specific type has to be created, or make use of the clone idiom if a polymorphic copy is needed. (If you are not afraid of Mad COW Disease, you could even try to figure out a generic COW solution.)

      Some very special cases might remain unsolved, but often the "Rule of The Big Zero" would be a good - and probably very attractive - solution.
      • Bjorn
         
        Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
        Re: The Rule of The Big Two
        October 4, 2004 3:37 AM      
        Hello Uwe,

        > Why stop here?
        >
        > Why not make it "The Rule of The Big Zero"?

        Hey, have you been reading through my drafts? ;-)

        > When the object is copied, you will either want to have
        > reference counting or deep copy semantic for its owned
        > resources.

        Yes.

        > If you opt for reference semantics, a suitable smart
        > pointer can just do it.

        Exactly.

        > To enable deep copy semantic, the smart pointer would need
        > to accept some copy mechanism function (object) pointer.
        > You would either use a creation function rsp. a factory
        > function if a specific type has to be created, or make use
        > of the clone idiom if a polymorphic copy is needed. (If
        > you are not afraid of Mad COW Disease, you could even try
        > to figure out a generic COW solution.)

        There are variations and techniques relating to create/clone/copy that make it possible to cover many use cases with little or no extra effort on behalf of the user.

        > Some very special cases might remain unsolved, but often
        > the "Rule of The Big Zero" would be a good - and probably
        > very attractive - solution.

        I agree. The general case is the "Law of the Big Three". The typical case is the "Law of the Big Two". The ideal case is the "Law? What Law?", but it typically comes at a cost in space and/or time (that may or may not be acceptable). More on this interesting topic in a future installment...

        Cheers,
        Bjorn
        • Uwe
           
          Posts: 4 / Nickname: uwe / Registered: August 27, 2003 8:00 PM
          Re: The Rule of The Big Two
          October 4, 2004 5:41 AM      
          > Hello Uwe,
          >
          > > Why stop here?
          > >
          > > Why not make it "The Rule of The Big Zero"?
          >
          > Hey, have you been reading through my drafts? ;-)

          No, I've been reading your mind. ;-)

          Sometimes, a C++ programmer MUST dive down through all these levels of abstraction, to get the optimum efficiency.

          > > When the object is copied, you will either want to have
          > > reference counting or deep copy semantic for its owned
          > > resources.
          >
          > Yes.
          >
          > > If you opt for reference semantics, a suitable smart
          > > pointer can just do it.
          >
          > Exactly.
          >
          > > To enable deep copy semantic, the smart pointer would
          > need
          > > to accept some copy mechanism function (object)
          > pointer.
          > > You would either use a creation function rsp. a factory
          > > function if a specific type has to be created, or make
          > use
          > > of the clone idiom if a polymorphic copy is needed. (If
          > > you are not afraid of Mad COW Disease, you could even
          > try
          > > to figure out a generic COW solution.)
          >
          > There are variations and techniques relating to
          > create/clone/copy that make it possible to cover many use
          > cases with little or no extra effort on behalf of the
          > user.

          Some of these techniques will look quite "alexandresque", won't they?

          > > Some very special cases might remain unsolved, but
          > often
          > > the "Rule of The Big Zero" would be a good - and
          > probably
          > > very attractive - solution.
          >
          > I agree. The general case is the "Law of the Big Three".
          > The typical case is the "Law of the Big Two". The ideal
          > case is the "Law? What Law?",

          This is sometimes called "true encapsulation".

          > but it typically comes at a
          > cost in space and/or time (that may or may not be
          > acceptable). More on this interesting topic in a future
          > installment...

          I'm looking forward ...

          > Cheers,
          > Bjorn

          Cheers,

          Uwe
    • Mehul
       
      Posts: 1 / Nickname: mehul / Registered: October 4, 2004 6:41 AM
      Re: The Law of The Big Two
      October 4, 2004 10:48 AM      
      I think smart_ptr's are worth every penny and your law of big 2 will work most of the time. However if someone uses the law of the two in a base class from which a heirarchy of classes are derived then the 'virtual' aspect of the destructor will be lost. Also the compiler will generate non-virtual destructors for all derived classes. This will be a very bad thing.

      Of course to correct this they need to declare the base classes' destructor virtual, in which case the compiler will generate virtual destructors
      • Steve
         
        Posts: 8 / Nickname: essennell / Registered: September 7, 2004 10:19 PM
        Re: The Law of The Big Two
        October 4, 2004 10:22 PM      
        > Of course to correct this they need to declare the base
        > classes' destructor virtual, in which case the compiler
        > will generate virtual destructors

        Well one school of thought recommends not deriving from classes with no virtual DTR ;-) (or alternatively always give classes you intend to be derived from a virtual DTR).
        • Matthew
           
          Posts: 20 / Nickname: bigboy / Registered: June 14, 2004 10:43 AM
          Re: The Law of The Big Two
          October 4, 2004 10:44 PM      
          > > Of course to correct this they need to declare the base
          > > classes' destructor virtual, in which case the compiler
          > > will generate virtual destructors

          > Well one school of thought recommends not deriving from
          > classes with no virtual DTR ;-) (or alternatively always
          > give classes you intend to be derived from a virtual DTR).

          That's generally excellent advice in runtime polymorphic (aka "classic") C++ world. However, it's a little too coarse-grained, IMO. If you're dealing with types with value semantics, then they're not likely to be in a (well-written) runtime-polymorphic hierarchy. As such, you're unlikely to be deleting them, if at all, via base class pointers.

          I think this is especially the case in template-world. It's very useful to be able to apply a compile-time adaptation to (value) types, via templates that inherit from their parameterising types. Again, such types are not going to be deleted by pointers to base class, so there's no need to encumber original class or composite with a vtable.

          Naturally, it's open to abuse, but that's why I'm stressing value types. It's most certainly the case that this could be abused if applied to (runtime polymorphic) entity types.
          • Steve
             
            Posts: 8 / Nickname: essennell / Registered: September 7, 2004 10:19 PM
            Re: The Law of The Big Two
            October 5, 2004 1:59 AM      
            > That's generally excellent advice in runtime polymorphic
            > (aka "classic") C++ world. However, it's a little too
            > coarse-grained, IMO. If you're dealing with types with
            > value semantics, then they're not likely to be in a
            > (well-written) runtime-polymorphic hierarchy. As such,
            > you're unlikely to be deleting them, if at all, via base
            > class pointers.

            Well that was my point ;-) Value types will not (generally) have virtual DTRs, so you shouldn't (generally) derive from them.

            (And I don't know about "classic"; C++ has long been multi-paradigm)

            But it's a good point, well made. The difference between Value and Polymorphic/Entity/... behaviour is often not stressed enough.

            >
            > I think this is especially the case in template-world.
            > It's very useful to be able to apply a compile-time
            > adaptation to (value) types, via templates that inherit
            > from their parameterising types.

            Yes. The "Curiously Recurring Template Pattern". The base classes are generally mixin types in this case, tho, and have no state, just behaviour.

            > Again, such types are not
            > going to be deleted by pointers to base class, so there's
            > no need to encumber original class or composite with a
            > vtable.

            Agreed. My own practice is to make the DTR protected and non-virtual in the base, thus preventing any misuse.

            >
            > Naturally, it's open to abuse, but that's why I'm
            > stressing value types. It's most certainly the case that
            > this could be abused if applied to (runtime polymorphic)
            > entity types.

            When I say "Classes you intend to derive from" I mean "Polymorphic and/or Entity Types"; I should have made that clearer. By Entity Types I mean types generally used to indicate behavioural contract, like Interfaces.

            Steve
            • Matthew
               
              Posts: 20 / Nickname: bigboy / Registered: June 14, 2004 10:43 AM
              Re: The Law of The Big Two
              October 5, 2004 2:51 AM      
              > > That's generally excellent advice in runtime polymorphic
              > > (aka "classic") C++ world. However, it's a little too
              > > coarse-grained, IMO. If you're dealing with types with
              > > value semantics, then they're not likely to be in a
              > > (well-written) runtime-polymorphic hierarchy. As such,
              > > you're unlikely to be deleting them, if at all, via base
              > > class pointers.
              >
              > Well that was my point ;-) Value types will not (generally)
              > have virtual DTRs, so you shouldn't (generally) derive from them.

              Well, I think the point I was making was that because value types
              should not be dealt with polymorphically anyway, there's no reason
              to *not* derive from them, except for the fact that it might incline
              the unwary to start treating them polymorphically.

              Personally, I'm quite happy with doing so via templates, but I still
              get an uneasy feeling seeing it done in a non-template way. (Too much
              exposure to clients' codebases containing classes deriving from
              std::string in order to provide an implicit conversion
              operator a la CString. Groan ...)

              > (And I don't know about "classic"; C++ has long been multi-paradigm)

              Fair point. ;)

              Maybe it's old farts like me that have spent so many years playing
              around before templates were widely usable.

              > But it's a good point, well made. The difference between Value and
              > Polymorphic/Entity/... behaviour is often not stressed enough.

              Agreed. (<blatant>My new book does make this distinction, and looks
              a little deeply into the meaning of value types</blatant>)

              > > I think this is especially the case in template-world.
              > > It's very useful to be able to apply a compile-time
              > > adaptation to (value) types, via templates that inherit
              > > from their parameterising types.
              >
              > Yes. The "Curiously Recurring Template Pattern". The base classes are
              > generally mixin types in this case, tho, and have no state, just behaviour.

              While CRTP is most certainly an example of what I'm talking about, it's
              more specialised. The idea I'm talking about is not necessarily recursive.
              It looks like the following:

              template <class T>
              class X
                : public T
              {
                . . . // blah blah
              };
               
              class SomeValueType
              {
              };
               
              typedef X<SomeValueType>  better_value_t;
              

              In my book <sorry, I don't mean to be such a tool ;)> I discuss the concepts
              of Veneers and Bolt-ins, which both follow this pattern. Veneers are the
              things we're talking about here, for adapting/adorning value-types, since
              they are not allowed to add non-static member variables, and must respect
              the polymorphic nature of their primary parameterising type.

              An example from the STLSoft libs is the mfcstl::cstring_veneer, which adapts
              the old CString class into something with a std::basic_string<>-like interface,
              i.e. c_str(), iterators, etc.

              > > Again, such types are not
              > > going to be deleted by pointers to base class, so there's
              > > no need to encumber original class or composite with a
              > > vtable.
              >
              > Agreed. My own practice is to make the DTR protected and non-virtual in the
              > base, thus preventing any misuse.

              Agreed. Herb's new book - Exceptional C++ Style - talks about this specifically.

              > > Naturally, it's open to abuse, but that's why I'm
              > > stressing value types. It's most certainly the case that
              > > this could be abused if applied to (runtime polymorphic)
              > > entity types.
              >
              > When I say "Classes you intend to derive from" I mean "Polymorphic and/or
              > Entity Types"; I should have made that clearer. By Entity Types I mean
              > types generally used to indicate behavioural contract, like Interfaces.

              Agreed.
              • Steve
                 
                Posts: 8 / Nickname: essennell / Registered: September 7, 2004 10:19 PM
                Re: The Law of The Big Two
                October 5, 2004 3:55 AM      
                I think we're in violent agreement (or close to it) ;-)

                Is this getting off-topic?

                > way. (Too much
                > exposure to clients' codebases containing classes deriving
                > from
                > std::string in order to provide an implicit
                > conversion
                > operator a la CString. Groan ...)

                Yup. Or std::vector<> to get a public Length "Property". I've seen 'em!

                > Maybe it's old farts like me that have spent so many years
                > playing
                > around before templates were widely usable.

                >8^>

                > In my book <sorry, I don't mean to be such a tool ;)>

                OK OK, it's been on my to-get list for a while, I admit.

                > discuss the concepts
                > of Veneers and Bolt-ins, which both follow
                > this pattern.

                These (and CRTP) are arguably expert-level, best kept well under the covers. STLSoft is a library, and these techniques have a place there, in much the same way as allocators in the Standard Lib (albeit with more utility ;-).

                > [me] ...so you shouldn't (generally) derive from them.

                hence the "generally".

                > > Agreed. My own practice is to make the DTR protected and
                > non-virtual in the
                > > base, thus preventing any misuse.
                >
                > Agreed. Herb's new book - Exceptional C++ Style -
                > talks about this specifically.

                Well I don't have that book, but I definitely picked up the technique from Herb amongst others. Kevlin Henney seems a likely candidate.
    • Vesa
       
      Posts: 5 / Nickname: vkarvone / Registered: June 14, 2004 5:19 AM
      Re: The Rule of The Big Two
      October 2, 2004 9:49 AM      
      I just wanted to note that the delete -operator does nothing if the pointer given to it is 0. This means that the checks in the following code snippet taken verbatim from the article are unnecessary.
          if (p_)
            delete p_;
          if (p2_)
            delete p2_;
      

      I mention this, because many unnecessary "safety idioms", like this, get picked up by newbie programmers. Unnecessary checks only increase code complexity.
      • Matthew
         
        Posts: 20 / Nickname: bigboy / Registered: June 14, 2004 10:43 AM
        Re: The Rule of The Big Two
        October 3, 2004 3:14 PM      
        Agreed, with contrition <g>. We'll ask Chuck to amend the article so.
        • Matthew
           
          Posts: 20 / Nickname: bigboy / Registered: June 14, 2004 10:43 AM
          Re: The Rule of The Big Two
          October 3, 2004 3:18 PM      
          Gah! I'd expected that the reply I just made would have been sub-threaded, or some such, to indicate which post it was a response to.

          It was responding to the comment regarding the redundant ifs around the deletions
          • Vincent
             
            Posts: 40 / Nickname: vincent / Registered: November 13, 2002 7:25 AM
            Re: The Rule of The Big Two
            October 5, 2004 4:02 AM      
            It was threaded correctly.

            You need to turn on the 'Threaded view' option at the top of the page.

            V.
    • Todd
       
      Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
      I'm blown away
      October 7, 2004 2:42 PM      
      that this is still the state of discourse in C++.

      Frozen in time for something like 10 years. Still no standard reference counting pointer implementation? Auto_ptr is weird and error prone and this level of fiddling is just madness.

      Providing optional GC would be a big win. Providing useful (and standard) counted and counting_ptr pairs would fix a ton of systems, but we are still fooling around with this?

      Color me disgusted.
      • Chuck
         
        Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
        Re: I'm blown away
        October 7, 2004 7:55 PM      
        > Providing optional GC would be a big win. Providing
        > useful (and standard) counted and counting_ptr pairs
        > would fix a ton of systems, but we are still fooling
        > around with this?
        >
        > Color me disgusted.

        Well, an attractive collection of smart pointers has been added to C++0x that would make you quite happy, and GC is under discussion. (Color yourself updated.) But in the meantime, we need to get by.
      • Steve
         
        Posts: 8 / Nickname: essennell / Registered: September 7, 2004 10:19 PM
        Re: I'm blown away
        October 7, 2004 10:38 PM      
        > that this is still the state of discourse in C++.
        >
        > Frozen in time for something like 10 years.

        Well folks have been working hard in that time for a "new release" of the standard, which seems likely to contain a decent - and useful - collection of pointer wrappers, including counting ones.

        If the language had been moving at the rate it was pre 1997, would you have preferred it?

        > Still no
        > standard reference counting pointer implementation?
        > Auto_ptr is weird and error prone and this level of
        > f fiddling is just madness.

        Ah well, auto_ptr has its uses though. Less wierd I reckon than strtok. And less error prone ;-)

        > Providing optional GC would be a big win.

        I'm still bemused by the amount of people who think automatic GC is some kind of silver bullet (I'm not suggesting you are one of them). I write in C# and C++ a lot, and I prefer C++'s deterministic destruction. For one thing, it makes exceptions much easier to think about.

        Steve
    • Bronek
       
      Posts: 1 / Nickname: brok / Registered: October 18, 2004 9:37 PM
      Re: The Law of The Big Two
      October 19, 2004 2:03 AM      
      There's one misleading sentence in the article:

      Another way of prohibiting copy construction and copy assignment is to make one or more members a reference or const (or const reference, for the especially cautious)—this effectively shuts down the compiler's ability to generate these special member functions

      As far as I remember, const or ref members won't disable copy constructor implicitly generated by compiler. It will only disable implicit copy assignment operator, or (more precisely) render program ill-formed when implicitly generated by compiler copy assignment operator is used.
    • alex
       
      Posts: 1 / Nickname: ipodhelp / Registered: January 24, 2005 8:40 AM
      Re: The Law of The Big Two
      January 25, 2005 1:51 PM      
      can you help me by doing this referal for getting a free ipod or pc you chose..... Just sign in and complet the recomended Call wave form and i will guide you so no personal info is given..at the end(with just referring some people) of the we will both have and ipod and its not a fake..please !http://www.freeiPods.com/?r=14135080

      http://www.FreeDesktopPC.com/?r=14319525

      http://www.FreeFlatScreens.com/?r=14321387

      Thanks
    • Daniel
       
      Posts: 5 / Nickname: teske / Registered: October 3, 2004 4:54 PM
      Re: The Rule of The Big Two
      October 3, 2004 11:09 PM      
      I understand why the authors didn't want to use auto_ptr, but the standard has another less known smart pointer:
      const auto_ptr<>

      const auto_ptr<> doesn't allow copy constructing and operator=. (Because both take a non-const reference).
      It can't release() its ownership and it can't be reset().

      The only valid constructor for const auto_ptr takes a plain pointer. So a const auto_ptr accuires ownership at the point of construction and owns the object until its destruction.

      const auto_ptr<> fits RAII better than auto_ptr<>.
      Because const auto_ptr<> has a very clear meaning, it should be used where possible. (The example isn't fleshed out enough to say for sure if it could be used.)
      • Bjorn
         
        Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
        Re: The Rule of The Big Two
        October 4, 2004 0:14 AM      
        > I understand why the authors didn't want to use auto_ptr,
        > but the standard has another less known smart pointer:
        > const auto_ptr<>

        Good point! But having a member of type const auto_ptr makes implementing the copy assignment operator problematic.

        > const auto_ptr<> doesn't allow copy constructing and
        > operator=. (Because both take a non-const reference).
        > It can't release() its ownership and it can't be reset().

        Exactly. This is a nice idiom for managing scoped resources (although boost::scoped_ptr is a better choice, in my opinion).

        > const auto_ptr<> fits RAII better than auto_ptr<>.
        > Because const auto_ptr<> has a very clear meaning, it
        > should be used where possible. (The example isn't fleshed
        > out enough to say for sure if it could be used.)

        It couldn't, due to the copy assignment operator. But a future article talks about this very topic, including the use of const auto_ptr.

        Cheers,
        Bjorn
        • Daniel
           
          Posts: 5 / Nickname: teske / Registered: October 3, 2004 4:54 PM
          Re: The Rule of The Big Two
          October 4, 2004 2:03 AM      
          >It couldn't, due to the copy assignment operator.
          Hmm, I don't quite understand where the problem is.

          class Example calls SomeResource.operator=() to copy p_ and p2_. Right?
          And i see no reason why a Example class using const auto_ptr<> couldn't use SomeRessource.operator=().
          So what's wrong with this:
          class Example {   
              const auto_ptr<SomeResource> p_;
          const auto_ptr<SomeResource> p2_;

          ...
            Example& operator=(const Example& other) {
          // Self assignment?
          if (this==&other)
          return *this;
                *p_  = *other.p_;
          *p2_ = *other.p2_;
                return *this;
          }



          >boost::scoped_ptr
          Well scoped_ptr and const auto_ptr<> are more or less the same.
          • Bjorn
             
            Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
            Re: The Rule of The Big Two
            October 4, 2004 3:30 AM      
            > >It couldn't, due to the copy assignment operator.
            > Hmm, I don't quite understand where the problem is.

            The problem in the general case is that the auto_ptr must always own a dynamically allocated object that supports (copy) assignment.

            In this case, the above is always true, so const auto_ptr would indeed have worked.

            > Well scoped_ptr and const auto_ptr<> are more or less the
            > same.

            There are a couple of differences that I think are important:

            * A scoped_ptr can be reset, a const auto_ptr cannot.
            * A const auto_ptr requires the reader of the code to recognize the importance of the constness, whereas scoped_ptr is always true to its name, and simply does not transfer ownership, period.

            Cheers,
            Bjorn
          • Marsha
             
            Posts: 1 / Nickname: mkpros / Registered: November 17, 2007 9:31 AM
            Re: The Rule of The Big Two
            November 17, 2007 3:36 PM      
            Iam loooking for a Dan Teske from Cleveland Ohio .1969 Grad. of Rhodes High School / St. Thomas More 1965. Please advise if you r him ...Marsha PROS Gorman
    • sapa
       
      Posts: 1 / Nickname: sapa / Registered: February 17, 2005 2:27 AM
      Re: The Law of The Big Two
      February 17, 2005 7:39 AM      
      I realize this is a newbie question, but does this code cause a leak for the old value of p_?

      Example& operator=(const Example& other) {
      // Self assignment?
      if (this==&other)
      return *this;

      *p_=*other.p_; // Uses SomeResource::operator=
      return *this;
      }
      • m
         
        Posts: 3 / Nickname: mlimber / Registered: November 2, 2006 6:37 AM
        Re: The Law of The Big Two
        May 9, 2008 9:32 AM      

        I realize this is a newbie question, but does this code cause a leak for the old value of p_?

        Example& operator=(const Example& other) {
        // Self assignment?
        if (this==&other)
        return *this;

        *p_=*other.p_; // Uses SomeResource::operator=
        return *this;
        }


        With all the indirection going on, it's a bit tricky to see, but there's no leak here. The reason is that there's no memory allocation or deallocation, only copying of values. That is, the assignment statement ("*p_=*other.p_;") is copying the value of other's p_ into the location currently pointed to by this's p_. Their allocation remains the same.

        A simplified example:


        int *i = new int(42);
        int *i2 = new int(2008);

        *i = *i2; // no leak here; just copying values

        delete i2;
        delete i;