The rule of the big three (and a half) – Source code

This is my first article in English on this blog so please be forgiving.

I recently read a C++ article about The rule of the big three (and a half) and I took the time to make sure the code snippets of the article works on my PC.

Indeed the evil is always in the details and it usually help me a lot to practice when I’m learning something new. Anyway, here is what I came with.

Each source code is complete, meaning you should be able to copy paste it directly. I only tested the code under Visual Studio Community 2013. Obviously the source code below only make sense if you read the article and play with your compiler at the same time. In few places I added few comments that may help the reader.

This is a zip with the solution and the projects : RuleOf3.5

Snippet 1 :

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
                                                                                // The "new" above in the members initialization list create the Socket
  pSocket->open();                                                             
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;                                                               // Destroy the Socket
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {
 
  {                                                                             // The block allow to see messages from ctor & dtor
    SocketManager mgr{ 2002, 0x7F000001 };
    mgr.send("Hello World.");
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 2

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager mgr1{ 2002, 0x7F000002 };
    SocketManager mgr2{ mgr1 };                                                 // Explicit copy contruction
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 3

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                    // Do NOT enable this line in order to declare "SocketManager mgr;" in main(). If so no assertion failed at runtime
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager mgr1{ 2002, 0x7F000002 };
    SocketManager mgr2 = mgr1;                                                  // Calls cpy ctor NOT operator=
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 4

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                  // Do NOT enable this line in order to declare "SocketManager mgr;" in main(). If so no assertion failed at runtime
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
void func(SocketManager mgr) {                                                  // Note : pass by value
  mgr.send("Hello World from func()");
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager mgr{ 2002, 0x7F000002 };
    func(mgr);
    mgr.send("Hello World from main()");
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 5

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
SocketManager make_SocketManager(const IPAddress& addr, const Port& port) {
  SocketManager temp{ addr, port };
  return temp;
}
 
SocketManager NRV_make_SocketManager(const IPAddress& addr, const Port& port) {
  return SocketManager{ addr, port };                                           // NRVO : Named Return Value Optimization
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager mgr1 = make_SocketManager(2002, 21);
    SocketManager mgr2 = NRV_make_SocketManager(2002, 21);
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 6

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
void preamble(SocketManager mgr) {                                              // Note : pass by value
  mgr.send("Hello World");
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager socketMgr{ 2002, 0x7F000001 };
    preamble(socketMgr);
    socketMgr.send("Hello World");
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 7

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
83
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                  // Do NOT enable this line in order to declare "SocketManager mgr;" in main(). If so no assertion failed at runtime
  SocketManager(const SocketManager& src);                                      // Cpy ctor
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
SocketManager::SocketManager(const SocketManager& src) : ip{ src.ip }, pSocket{ nullptr } {
                                                                                // Remember - use the MIL above (MIL = members initialization list)
  if (src.pSocket != nullptr) {
    pSocket = new Socket{ *src.pSocket };                                       // Copy conctruct the Socket object
  }
  pSocket->open();
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {                                                                    // Run in Debug mode. Generates an assertion failed
 
  {
    SocketManager mgr1{ 2002, 0x7F000001 };;
    SocketManager mgr2 = mgr1;                                                  // cpy ctor
 
    SocketManager mgr3{ 1001, 0x7F000011 };;
    mgr3 = mgr1;                                                                // This is where the problem is
 
    mgr1.send("Hello World");
    mgr2.send("Goodbye cruel world");
    mgr3.send("Am I still here?");
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 8

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
83
84
85
86
87
88
89
90
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                   
  SocketManager(const SocketManager& src);                                      // Cpy ctor
  SocketManager& operator=(const SocketManager& rhs);                           // Assignment operator 
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
  void swap(SocketManager& rhs);
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
SocketManager::SocketManager(const SocketManager& src) : ip{ src.ip }, pSocket{ nullptr } {
  if (src.pSocket != nullptr) {
    pSocket = new Socket{ *src.pSocket };
  }
  pSocket->open();
}
 
SocketManager& SocketManager::operator=(const SocketManager& rhs) {
  SocketManager temp{ rhs };                                                    // Cpy construct temp. Generates the third "Socket opened" message
  swap(temp);
  return *this;
}
 
void SocketManager::swap(SocketManager& rhs) {
  std::swap(this->ip, rhs.ip);                                                  // Swap each attribute
  std::swap(this->pSocket, rhs.pSocket);
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {
 
  {
    SocketManager mgr1{ 2002, 0x7F000001 };
    SocketManager mgr2{ 1441, 0x7F00007F };
 
    mgr2 = mgr1;
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 9

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
83
84
85
86
87
88
89
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                   
  SocketManager(const SocketManager& src);                                      // Cpy ctor
  SocketManager& operator=(SocketManager rhs);                                  // Pass by value and no longer const
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
  void swap(SocketManager& rhs);
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
SocketManager::SocketManager(const SocketManager& src) : ip{ src.ip }, pSocket{ nullptr } {
  if (src.pSocket != nullptr) {
    pSocket = new Socket{ *src.pSocket };
  }
  pSocket->open();
}
 
SocketManager& SocketManager::operator= (SocketManager rhs) {                   // Pass by value. No longer const
  swap(rhs);
  return *this;
}
 
void SocketManager::swap(SocketManager& rhs) {
  std::swap(this->ip, rhs.ip);
  std::swap(this->pSocket, rhs.pSocket);
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {
 
  {
    SocketManager mgr1{ 2002, 0x7F000001 };
    SocketManager mgr2{ 1441, 0x7F00007F };
 
    mgr2 = mgr1;
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}

Snippet 10

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
#include <iostream>
#include <limits>
 
using namespace std;
 
using Port      = int;
using IPAddress = int;
 
class Socket {
public:
  Socket(Port p);
  void open();
  void close();
  void write(const char *buf);
private:
  Port port;
};
 
Socket::Socket(Port p) : port{ p } {
}
 
void Socket::open() {
  cout << "Socket opened" << endl;
}
 
void Socket::close() {
  cout << "Socket closed" << endl;
}
 
void Socket::write(const char *buf) {
  cout << "Message sent : " << buf << endl;
}
 
class SocketManager {
public:
  SocketManager(IPAddress addr, Port p);
  ~SocketManager();
  //SocketManager() = default;                                                  
  SocketManager& operator=(SocketManager rhs) = delete;                         // No need to define these functions                      
  SocketManager(const SocketManager& src) = delete;                           
  void send(const char *str) const;
private:
  IPAddress ip;
  Socket *pSocket;
  void swap(SocketManager& rhs);
};
 
SocketManager::SocketManager(IPAddress addr, Port p) : ip{ addr }, pSocket{ new Socket{ p } } {
  pSocket->open();
}
 
SocketManager::~SocketManager() {
  pSocket->close();
  delete pSocket;
}
 
void SocketManager::swap(SocketManager& rhs) {
  std::swap(this->ip, rhs.ip);
  std::swap(this->pSocket, rhs.pSocket);
}
 
void SocketManager::send(const char *str) const {
  pSocket->write(str);
}
 
int main() {                                                                    // Does not compile. Indeed Cpy ctor is "deleted"
 
  {
    SocketManager mgr1{ 2002, 0x7F000001 };
    SocketManager mgr2{ 1441, 0x7F00007F };
 
    mgr2 = mgr1;
  }
 
  cout << "Press ENTER to quit : ";
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
}
Share this...

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.