Topic: Class with member swap and std::swap specialization still not Swappable?


Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Wed, 13 Sep 2006 12:36:47 CST
Raw View
Niels Dekker (no reply address) wrote:
> > Wouldn't it better to include any T as being Swappable for which the
> > following lines are valid, and have the right semantics?
> >   using std::swap;
> >   swap(t, u);  // t and u are values of type T
>
> Greg Herlihy replied:
> >
> > No, the second line all by itself should be valid:
> >
> >      swap( t, u );
> >
> > which is not the case in the above program. Because swap() has been
> > defined in the std namespace, it will not be found when passed
> > arguments of a class (Uncopyable) that has been declared in the global
> > namespace.
>
> Thank you.  So will std functions that have those Swappable requirements
> (e.g., std::iter_swap) give compile errors when I try to use them for
> objects of my Uncopyable class, even if it has a specialization for
> std::swap?

Even when a program fails to meet the Swappable requirement for a given
operation, it may still compile and even run as expected. There is just
no assurance - the code could compile but not work as expected. And it
is this kind of "silent failure" that is the real risk for not meeting
the requirements (see below).

> In other words, will the following program be rejected by C++0x?
> ------------------------------------------------------------------------
>   #include <algorithm>
>
>   class Uncopyable
>   {
>   public:
>     Uncopyable() {}
>     void swap(Uncopyable &) {}
>   private:
>     Uncopyable(const Uncopyable &);
>     Uncopyable& operator=(const Uncopyable&);
>   };
>
>   namespace std
>   {
>     template <>
>     void swap<Uncopyable>(Uncopyable& lhs, Uncopyable & rhs)
>     {
>       lhs.swap(rhs);
>     }
>   }
>
>   int main()
>   {
>     Uncopyable t, u;
>
>     std::iter_swap(&t, &u);  // Rejected by C++0x?
>   }

No, the code will compile and run as expected even though Uncopyable
has not met the Swappable requirements. However the results could well
be different if an (otherwise unrelated) swap() routine is declared in
the global namespace.

      void swap(Uncopyable& lhs, Uncopyable& rhs)
      {
         // do nothing interesting
      }

Now all calls to swap() that used to call the Uncopyable specialization
in the std namespace are now dispatched to this global swap() routine -
even though this routine does not meet the Swappable requirements. So
although the program will still compile and run - the addition of this
new routine means that it will no longer produce the expected results.

Whereas if the program had declared the required swap() routine in the
appropriate (that is, global) namespace to begin with - then this
unfortunate situation would have been avoided.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: unknown@this.is.invalid ("Niels Dekker (no reply address)")
Date: Wed, 13 Sep 2006 02:39:54 GMT
Raw View
Does the following class meet the Swappable requirement, according to
C++0x?  It has a public swap member function and a specialization of
std::swap.

  #include <algorithm>

  class Uncopyable
  {
  public:
    Uncopyable() {}
    void swap(Uncopyable &) {}
  private:
    Uncopyable(const Uncopyable &);
    Uncopyable& operator=(const Uncopyable&);
  };

  namespace std
  {
    template <>
    void swap<Uncopyable>(Uncopyable& lhs, Uncopyable & rhs)
    {
      lhs.swap(rhs);
    }
  }

If I understand the Draft well, this class is not Swappable.  Which
sounds rather counter-intuitive to me!
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf

Wouldn't it better to include any T as being Swappable for which the
following lines are valid, and have the right semantics?
  using std::swap;
  swap(t, u);  // t and u are values of type T

This corresponds to the way Scott Meyers recommands calling a swap
function, in Effective C++, 3rd Edition, item 25.


Kind regards,

  Niels Dekker
  www.xs4all.nl/~nd/dekkerware

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Tue, 12 Sep 2006 23:09:41 CST
Raw View
"Niels Dekker no reply address wrote:
> Does the following class meet the Swappable requirement, according to
> C++0x?  It has a public swap member function and a specialization of
> std::swap.
>
>   #include <algorithm>
>
>   class Uncopyable
>   {
>   public:
>     Uncopyable() {}
>     void swap(Uncopyable &) {}
>   private:
>     Uncopyable(const Uncopyable &);
>     Uncopyable& operator=(const Uncopyable&);
>   };
>
>   namespace std
>   {
>     template <>
>     void swap<Uncopyable>(Uncopyable& lhs, Uncopyable & rhs)
>     {
>       lhs.swap(rhs);
>     }
>   }
>
> If I understand the Draft well, this class is not Swappable.  Which
> sounds rather counter-intuitive to me!
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
>
> Wouldn't it better to include any T as being Swappable for which the
> following lines are valid, and have the right semantics?
>   using std::swap;
>   swap(t, u);  // t and u are values of type T

No, the second line all by itself should be valid:

     swap( t, u );

which is not the case in the above program. Because swap() has been
defined in the std namespace, it will not be found when passed
arguments of a class (Uncopyable) that has been declared in the global
namespace.

The fix therefore is to declare swap() in the same namespace as the one
in which Uncopyable is declared - whether that namespace is, as in this
case, the global namespace, or whether it is some other namespace that
the program has declared:

    void swap(Uncopyable& lhs, Uncopyable & rhs)
    {
        lhs.swap(rhs);
    }

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jth02@arcor.de (Jens Theisen)
Date: Wed, 13 Sep 2006 14:54:15 GMT
Raw View
"Greg Herlihy" <greghe@pacbell.net> writes:

> > Wouldn't it better to include any T as being Swappable for which the
> > following lines are valid, and have the right semantics?
> >   using std::swap;
> >   swap(t, u);  // t and u are values of type T

This recommendation is there in case you can't be sure that t and u
are not defined in the global namespace - there nothing will be found
by ADL. Stuff in you namespaces and namespace std are fine.

Jens

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Wed, 13 Sep 2006 11:29:21 CST
Raw View
In article <45072852.3A818711@this.is.invalid>,
 unknown@this.is.invalid ("Niels Dekker (no reply address)") wrote:

> Does the following class meet the Swappable requirement, according to
> C++0x?  It has a public swap member function and a specialization of
> std::swap.
>
>   #include <algorithm>
>
>   class Uncopyable
>   {
>   public:
>     Uncopyable() {}
>     void swap(Uncopyable &) {}
>   private:
>     Uncopyable(const Uncopyable &);
>     Uncopyable& operator=(const Uncopyable&);
>   };
>
>   namespace std
>   {
>     template <>
>     void swap<Uncopyable>(Uncopyable& lhs, Uncopyable & rhs)
>     {
>       lhs.swap(rhs);
>     }
>   }
>
> If I understand the Draft well, this class is not Swappable.  Which
> sounds rather counter-intuitive to me!
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
>
> Wouldn't it better to include any T as being Swappable for which the
> following lines are valid, and have the right semantics?
>   using std::swap;
>   swap(t, u);  // t and u are values of type T
>
> This corresponds to the way Scott Meyers recommands calling a swap
> function, in Effective C++, 3rd Edition, item 25.

Thanks Niels.  I think you make a good point.  I've opened LWG issue 594.

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]