Bad alloc exception from copy cons?

Pages: 12
(I double posted, see the post on the previous page as well. Whoops.)

but lets say an object had another object as a member variable(which also called swap() in its operator= function) as in composition,that means we couldn't use the std::swap() function? because std::swap would call the assignment operator on that object right?

If a swappable type in the C++ standard library exists, the standard library should either use std::swap correctly, or a specialization of std::swap. I think. (A class can also be not assignable on purpose, and therefore not swappable by std::swap, and it will be a compilation error, but still not infinite recursion.)

If, within your class, you have another custom class object that uses its own swap in its implementation of its assignment operator, that type will have to swap each component of that custom class. Your class shouldn't have to worry about how that class implements its assignment operator or swap function if you use the "using std::swap;" construct and that custom class follows the guidelines in http://en.cppreference.com/w/cpp/concept/Swappable

any standard library functions (for example, many algorithms) expect their arguments to satisfy Swappable, which means that any time the standard library performs a swap, it uses the equivalent of using std::swap; swap(t, u);.

Typical implementations either

1) Define a non-member swap in the enclosing namespace, which may forward to a member swap if access to non-public data members is required
2) Define a friend function in-class (this approach hides the class-specific swap from name lookup other than ADL)


I think it would be best to just try making what you described, and you'll see what works and what goes awry. And if some specific breaks and you're not sure why, ask away and I or someone that's an expert in assignments/swapping can explain why :)

(The alternative is to also not use swap to implement operator=. Sometimes it's cleaner, other times not).
Last edited on
yup crash!

that is a pretty nasty bug,I mean its something that many people could easily do what it out realising it.

also I never knew a move assignment operator even existed until Icys post :O

If, within your class, you have another custom class object that uses its own swap in its implementation of its assignment operator, that type will have to swap each component of that custom class.


good point,never even thought of that it may be a bit tedious though

thanks guys :) I don't think I have any more questions for now :)
Last edited on
Just to clarify I will try keep it as brief as possible from what I now understand

in the example where we use the assignment operator a = b;

first the operator= will be called inside this std::swap(a,b) will be called inside std::swap(a,b) the operator= will be cause because person temp = a; a = b; b = temp;

because temp = a uses the operator= from the person object persons operator= will again again call swap which then calls std::swap std::swap then calls swap again and this pattern keeps on going causing infinite recursion right?

but to avoid this we can make an object non copyable by making the operator= function private or even protected.


thanks
In the buggy recursive example (on the end of page 1), std::swap is never called. You are doing a simple tail-end recursion of your swap function.

If you specifically wrote std::swap(a, b); instead of using std::swap; swap(a,b);, then your explanation would be correct pattern (operator= calls std::swap, calls operator=, calls std::swap, ...) keeps on going). Edit: I'm wrong, it seems to be calling std::swap either way. Either way, infinite recursion though.

Making an object non-copyable is an extreme "solution", the key here is to make sure you don't implement Person::operator=(Person) by using std::swap(Person&, Person&). Usually, things are made non-copyable for other reasons, to prevent abuse of functionality, for example std::mutex is non-copyable.
Last edited on

If you specifically wrote std::swap(a, b); instead of using std::swap; swap(a,b);, then your explanation would be correct pattern (operator= calls std::swap, calls operator=, calls std::swap, ...) keeps on going). Either way, infinite recursion though.


but when I call swap() with each persons member variables,it actually works

the code below prints hii and also when I tried to print the name jim it printed the name jim,so everything seems to be swapped correctly? maybe it's something my compiler is doing?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdio.h>
#include <iostream>
#include <cstring>

using namespace std;

class person{

     public:

     string name;
     int age;
     char* cstr;
     int len;

     person(string n,int a,const char* c)
     {
         name = n;
         len = strlen(c)+1;
         age = a;
         cstr = new char[len];
         memcpy(cstr,c,len);
     }
     person(){

     }

     person(const person &other){

         name = other.name;
         age = other.age;
         len = other.len;
         cstr = new char[len];
         memcpy(cstr,other.cstr,len);
     }
     person(person &&other){

         name = other.name;
         age = other.age;
         len = other.len;
         cstr = other.cstr;
         other.cstr = nullptr;
     }

     person& operator=(person other){

        swap(*this,other);
        return *this;

     }

     void swap(person& one,person &two){

        using std::swap;
        swap(one.name,two.name);
        swap(one.age,two.age);
        swap(one.len,two.len);
        swap(one.cstr,two.cstr);
     }

     ~person(){

        delete[] cstr;
     }
};

int main()
{
  person a("adam",26,"hello");
  cout << a.len << endl;
  person b = a;
  cout << b.name << endl;
  person c = a;
  cout << c.name << endl;
  c = b;  // Cop=(b);
  cout << "try now :: " << c.name << endl;
  cout << "try again :: " << c.cstr << endl;
  c = person("jim",37,"hii");

  cout << c.cstr << endl; // prints hi
  cout << c.name << endl; // prints jim
}

Last edited on
Your swap looks correct there. That is indeed calling std::swap(std::string&, std::string), std::swap(int&, int&), std::swap(int&, int&) and std::swap(char*&, char*&). You're swapping each component, so everything is peachy.

But I was also slightly wrong, your example at the end of page one does actually still call std::swap, assignment operator, swap, std::swap, assignment operator...
1
2
3
4
5
6
7
8
9
10
11
This will infinitely recurse until a crash:
Person assignment
  Person swap
   std::swap
     Person assignment
       Person swap
         std::swap
           Person assignment
             Person swap
               std::swap
                 Person assignment


So ignore the parts of the conversation where I said it was simply tail-end recursion and not cyclic recursion. I thought it would prefer the explicit version before the template version, but my hypothesis was wrong. Everything else I said (the main point, that it recurses) is still correct, though.

Last edited on
thanks Ganado much appreciated I know have a decent understanding of this topic :)

So ignore the parts of the conversation where I said it was simply tail-end recursion and not cyclic recursion. I thought it would prefer the explicit version before the template version, but my hypothesis was wrong. Everything else I said (the main point) is still correct, though.


probably depends on what compiler you are using
Last edited on
may have been a different story if I used a different compiler,

my compiler is mingGW and running on a 64 bit windows 10 machine using codeblocks

thanks for all the help you are awesome!!! :)
I think we're talking about two different things. Like I said, the overload resolution of which function it chooses is precisely defined in the standard, I just don't exactly understand how it makes the decision. If one compiler does something different when it comes to overload resolution, it is wrong. But that's not what's happening here, your compiler is not wrong. Maybe I'll ask it as a question in another thread.
Last edited on
good idea :)

could you post the link to it in this thread

thanks
Topic archived. No new replies allowed.
Pages: 12