Thread: std::swap( _Tp&, _Tp& ) calling copy constructor

  1. #1
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391

    std::swap( _Tp&, _Tp& ) calling copy constructor

    I've made the copy constructor private in one of my classes and i'm getting a compiler error informing me that std::swap is trying to call the copy constructor.

    is there a way to make the std::swap a friend of the class? I couldn't get it to do it.

    I tried:
    Code:
    friend void std::swap( MyClass&, MyClass& )
    but gcc tells me swap should've been declared in std.

    Any ideas?

    BTW: this is the swap in <algorithm> if it makes any difference
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  2. #2
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    maybe something like:

    Code:
    class Myclass {
       Myclass(const Myclass&);
    public:
       void swap(Myclass& other) {
          // Your implementation of swap here
       }
    };
    
    
    namespace std {
       void swap(Myclass& left, Myclass &right) {
          left.swap(right);
       }
    }

  3. #3
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Well I'd rather not re-implement "swap" since the one in <algorithm> does exactly what I want it to.

    and why would i want to declare another namespace called std?
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Why not implement a MyClass::swap()? That's how it's typically handled.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Quote Originally Posted by brewbuck View Post
    Why not implement a MyClass::swap()? That's how it's typically handled.
    Because it's being called by another class which has a container of the class in question. Basically like this:
    Code:
    class Foo{
    private:
      Foo( const Foo& );
    };
    
    class Bar{
      std::vector<Foo> foo_vec;
    public:
      void fxn(){
        for( int i = 0; i < foo_vec.size(); i++ )
          std::swap( foo_vec[i],   foo_vec[get_rand_int(0,foo_vec.size())]);
    }
    a shuffling method if you will
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Why is the copy constructor private?

    If you use brewbuck's idea then you just change it to:
    Code:
    foo_vec[i].swap(foo_vec[get_rand_int(0,foo_vec.size())]);
    but it sounds fishy that you can swap but not copy.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by dudeomanodude View Post
    Because it's being called by another class which has a container of the class in question. Basically like this:
    Then you should provide a specialization of std::swap() which will just invoke your MyClass::swap().
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    Quote Originally Posted by dudeomanodude View Post
    Well I'd rather not re-implement "swap" since the one in <algorithm> does exactly what I want it to.
    No it doesn't. This is what std::swap does:

    Code:
    template<class T>
    void swap(T& left, T& right) {
       T tmp = left;
       left = right, right = tmp;
    }
    Which calls the copy constructor (And fails if it's private, as in your example)

    If you implement a swap method, you don't suffer from this problem (And you can also avoid extra copies)

    and why would i want to declare another namespace called std?
    I'm not declaring another namespace std. I'm extending the already existing namespace with the specialized swap<Myclass>

  9. #9
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Why is the copy constructor private?

    If you use brewbuck's idea then you just change it to:
    Code:
    foo_vec[i].swap(foo_vec[get_rand_int(0,foo_vec.size())]);
    but it sounds fishy that you can swap but not copy.
    I think I'll just reimplement the copy ctor to avoid what it is i'm trying to avoid...
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by dudeomanodude
    I think I'll just reimplement the copy ctor to avoid what it is i'm trying to avoid...
    Remember to implement the copy assignment operator as well. Actually, you might as well go ahead with the advice to implement a member swap and then implement the copy assignment operator in terms of the copy constructor, member swap and destructor... and also specialise std::swap using your member swap.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    Two things:

    1. I implemented a member swap, and it still fails with the private copy ctor, even though the class calling it is a friend. Example:
    Code:
    class Foo{
        Foo( const Foo& );
        friend class Bar;
      public:
        void swap( Foo& right ){
          Foo temp = *this;
          *this = right, right = temp;
        }
    };
    
    class Bar{
      public:
        void shuffle( Foo& left, Foo& right ){
          left.swap( right );
        }
    };
    I really do need a private copy ctor/assignment optor because (in my actual program)Foo holds a pointer to Bar, which identifies the Foo's origin. If a Bar makes a Foo, the Foo get's the Bar's this-> pointer, if a Foo is created on its own, it's Bar pointer stays null. Now the problem I'm having is that if I overload Foo's copy ctor to make the Bar pointer null, then the implementation of shuffle is completely hosed. Any ideas for this situation are most appreciated.

    2. Where do I extend std::swap? I get a multiple definition error if I try to in Foo's header. I've never done that before, so is there any guidelines with extending namespaces in this fashion?
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by dudeomanodude
    1. I implemented a member swap, and it still fails with the private copy ctor, even though the class calling it is a friend.
    Friendship no longer matters since the member swap is a public member function. Instead of implementing the member swap in terms of the copy constructor and copy assignment operator, implement it to actually swap the members. You are probably getting linker errors at the moment because the copy constructor is declared but not implemented (and you forgot to declare the copy assignment operator as private).

    Quote Originally Posted by dudeomanodude
    Now the problem I'm having is that if I overload Foo's copy ctor to make the Bar pointer null, then the implementation of shuffle is completely hosed.
    I do not get your reasoning. The copy constructor would not make the Bar pointer null, but would make the bar pointer a copy of the bar pointer of the source Foo object.

    Quote Originally Posted by dudeomanodude
    2. Where do I extend std::swap? I get a multiple definition error if I try to in Foo's header. I've never done that before, so is there any guidelines with extending namespaces in this fashion?
    Do something like this:
    Code:
    namespace std
    {
        template<>
        void swap<Foo>(Foo& a, Foo& b)
        {
            a.swap(b);
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Use this: dudeomanodude's Avatar
    Join Date
    Jan 2008
    Location
    Hampton, VA
    Posts
    391
    You are probably getting linker errors at the moment because the copy constructor is declared but not implemented (and you forgot to declare the copy assignment operator as private).
    No. I've declared both, and implemented both.

    I do not get your reasoning. The copy constructor would not make the Bar pointer null, but would make the bar pointer a copy of the bar pointer of the source Foo object.
    And this is exactly what I'm trying to avoid. If copying goes public, than yes, the copy semantics need to be re-written to make the Bar* null. I don't want to be able to copy a Foo from an existing Foo, and take it's Bar*( its originator ) along with it. Bar has a container of Foos. Bar can give out these Foos, it can also take them back. But it can only take them back if it came from it. That's the situation I'm trying to program here. So copying becomes a problem, especially now that I want to call swap. Before implementing shuffle, private copying was fine. Now, I've programmed myself into a corner.
    Ubuntu Desktop
    GCC/G++
    Geany (for quick projects)
    Anjuta (for larger things)

  14. #14
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Don't implement the swap method in terms of copy constructor (which std::swap already does). Instead, swap around the members contained within Foo. For example, a string would swap the pointers to the internal buffer (as well as the other data members) without constructing a third string.

    --------------

    As a side note, the following compiles with VC++ 2005, but not with MinGW 3.4.5. The latter uses std::iter_swap (which performs a swap using copy constructor) in std::random_shuffle and not std::swap. Is there anything that can be done about it and why on earth did they even need the iter_swap algorithm in the standard.

    Code:
    #include <algorithm>
    
    class X
    {
        X(const X&);
    public:
        X() {}
        void swap(X&) {}
    };
    
    namespace std
    {
    template <>
    void swap(X& a, X& b)
    {
        a.swap(b);
    }
    }
    
    int main()
    {
        X x[10];
        std::random_shuffle(x, x + 10);
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by dudeomanodude
    Bar has a container of Foos. Bar can give out these Foos, it can also take them back. But it can only take them back if it came from it.
    Okay, this makes things a little clearer. What do you mean by "give out these Foos" and "take them back"? Are you talking about copying semantics similiar to std::auto_ptr? What does it mean to swap two Foo objects? Why does Bar::shuffle merely swap two Foo objects apparently unrelated to the Bar object?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer conversion problems with a copy constructor
    By stanlvw in forum C++ Programming
    Replies: 8
    Last Post: 01-14-2008, 12:06 AM
  2. Copy constructor for Queue ADT (as an Array)
    By clegs in forum C++ Programming
    Replies: 2
    Last Post: 11-28-2007, 11:05 PM
  3. Copy Constructor
    By noobcpp in forum C++ Programming
    Replies: 3
    Last Post: 07-01-2007, 06:29 AM
  4. Replies: 2
    Last Post: 04-04-2007, 06:34 PM
  5. calling default instead of argument constructor, why?!
    By cppn00b in forum C++ Programming
    Replies: 6
    Last Post: 01-30-2005, 04:24 AM