23
23
24
24
namespace mbed {
25
25
26
+ /* * \addtogroup platform */
27
+ /* * @{*/
26
28
/* *
27
- * Inheriting from this class autogeneration of copy construction and copy
28
- * assignment operations.
29
- *
30
- * Classes which are not value type should inherit privately from this class
31
- * to avoid generation of invalid copy constructor or copy assignment operator
32
- * which can lead to unnoticeable programming errors.
33
- *
34
- * As an example consider the following signature:
35
- *
29
+ * \defgroup platform_NonCopyable NonCopyable class
30
+ * @{
31
+ */
32
+
33
+ /* *
34
+ * Prevents generation of copy constructor and copy assignment operator in
35
+ * derived classes.
36
+ *
37
+ * @par Usage
38
+ *
39
+ * To prevent generation of copy constructor and copy assignment operator,
40
+ * inherit privately from the NonCopyable class.
41
+ *
42
+ * @code
43
+ * class Resource : NonCopyable<Resource> { };
44
+ *
45
+ * Resource r;
46
+ * // generates compile time error:
47
+ * Resource r2 = r;
48
+ * @endcode
49
+ *
50
+ * @par Background information
51
+ *
52
+ * Instances of polymorphic classes are not meant to be copied. The
53
+ * C++ standards generate a default copy constructor and copy assignment
54
+ * function if these functions have not been defined in the class.
55
+ *
56
+ * Consider the following example:
57
+ *
36
58
* @code
37
- * class Resource;
38
- *
39
- * class Foo {
59
+ * // base class representing a connection
60
+ * struct Connection {
61
+ * Connection();
62
+ * virtual ~Connection();
63
+ * virtual void open() = 0;
64
+ * }
65
+ *
66
+ * class SerialConnection : public Connection {
40
67
* public:
41
- * Foo() : _resource(new Resource()) { }
42
- * ~Foo() { delete _resource; }
68
+ * SerialConnection(Serial*);
69
+ *
43
70
* private:
44
- * Resource* _resource;
71
+ * Serial* _serial;
72
+ * };
73
+ *
74
+ * Connection& get_connection() {
75
+ * static SerialConnection serial_connection;
76
+ * return serial_connection;
45
77
* }
46
78
*
47
- * Foo get_foo();
48
- *
49
- * Foo foo = get_foo();
79
+ * Connection connection = get_connection();
50
80
* @endcode
51
- *
52
- * There is a bug in this function, it returns a temporary value which will be
53
- * byte copied into foo then destroyed. Unfortunately, internally the Foo class
54
- * manage a pointer to a Resource object. This pointer will be released when the
55
- * temporary is destroyed and foo will manage a pointer to an already released
56
- * Resource.
57
- *
58
- * Two issues has to be fixed in the example above:
59
- * - Function signature has to be changed to reflect the fact that Foo
60
- * instances cannot be copied. In that case accessor should return a
61
- * reference to give access to objects already existing and managed.
62
- * Generator on the other hand should return a pointer to the created object.
63
- *
81
+ *
82
+ * There is a subtle bug in this code, the function get_connection returns a
83
+ * reference to a Connection which is captured by value instead of reference.
84
+ *
85
+ * When `get_connection` returns a reference to serial_connection it is copied into
86
+ * the local variable connection. The vtable and others members defined in Connection
87
+ * are copied, but members defined in SerialConnection are left apart. This can cause
88
+ * severe crashes or bugs if the virtual functions captured use members not present
89
+ * in the base declaration.
90
+ *
91
+ * To solve that problem, the copy constructor and assignment operator have to
92
+ * be declared (but don't need to be defined) in the private section of the
93
+ * Connection class:
94
+ *
64
95
* @code
65
- * // return a reference to an already managed Foo instance
66
- * Foo& get_foo();
67
- * Foo& foo = get_foo();
68
- *
69
- * // create a new Foo instance
70
- * Foo* make_foo();
71
- * Foo* m = make_foo();
72
- * @endcode
73
- *
74
- * - Copy constructor and copy assignment operator has to be made private
75
- * in the Foo class. It prevents unwanted copy of Foo objects. This can be
76
- * done by declaring copy constructor and copy assignment in the private
77
- * section of the Foo class.
78
- *
79
- * @code
80
- * class Foo {
81
- * public:
82
- * Foo() : _resource(new Resource()) { }
83
- * ~Foo() { delete _resource; }
96
+ * struct Connection {
84
97
* private:
85
- * // disallow copy operations
86
- * Foo(const Foo&);
87
- * Foo& operator=(const Foo&);
88
- * // data members
89
- * Resource* _resource;
98
+ * Connection(const Connection&);
99
+ * Connection& operator=(const Connection&);
90
100
* }
91
101
* @endcode
92
- *
93
- * Another solution is to inherit privately from the NonCopyable class.
94
- * It reduces the boiler plate needed to avoid copy operations but more
95
- * importantly it clarifies the programmer intent and the object semantic.
96
- *
97
- * class Foo : private NonCopyable<Foo> {
98
- * public:
99
- * Foo() : _resource(new Resource()) { }
100
- * ~Foo() { delete _resource; }
101
- * private:
102
- * Resource* _resource;
102
+ *
103
+ * Although manually declaring private copy constructor and assignment functions
104
+ * works, it is not ideal. These declarations are usually easy to forget,
105
+ * not immediately visible, and may be obscure to uninformed programmers.
106
+ *
107
+ * Using the NonCopyable class reduces the boilerplate required and expresses
108
+ * the intent because class inheritance appears right after the class name
109
+ * declaration.
110
+ *
111
+ * @code
112
+ * struct Connection : private NonCopyable<Connection> {
113
+ * // regular declarations
103
114
* }
104
- *
105
- * @tparam T The type that should be made non copyable. It prevent cases where
106
- * the empty base optimization cannot be applied and therefore ensure that the
107
- * cost of this semantic sugar is null.
108
- *
115
+ * @endcode
116
+ *
117
+ *
118
+ * @par Implementation details
119
+ *
120
+ * Using a template type prevents cases where the empty base optimization cannot
121
+ * be applied and therefore ensures that the cost of the NonCopyable semantic
122
+ * sugar is null.
123
+ *
109
124
* As an example, the empty base optimization is prohibited if one of the empty
110
- * base class is also a base type of the first non static data member:
125
+ * base classes is also a base type of the first nonstatic data member:
111
126
*
112
127
* @code
113
128
* struct A { };
@@ -121,11 +136,11 @@ namespace mbed {
121
136
* };
122
137
*
123
138
* // empty base optimization cannot be applied here because A from C and A from
124
- * // B shall have a different address. In that case, with the alignment
139
+ * // B have a different address. In that case, with the alignment
125
140
* // sizeof(C) == 2* sizeof(int)
126
141
* @endcode
127
142
*
128
- * The solution to that problem is to templatize the empty class to makes it
143
+ * The solution to that problem is to templatize the empty class to make it
129
144
* unique to the type it is applied to:
130
145
*
131
146
* @code
@@ -142,12 +157,15 @@ namespace mbed {
142
157
* // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
143
158
* @endcode
144
159
*
145
- * @note Compile time errors are disabled if the develop or the release profile
146
- * is used. To override this behavior and force compile time errors in all profile
160
+ * @tparam T The type that should be made noncopyable.
161
+ *
162
+ * @note Compile time errors are disabled if you use the develop or release profile.
163
+ * To override this behavior and force compile time errors in all profiles,
147
164
* set the configuration parameter "platform.force-non-copyable-error" to true.
148
165
*/
149
166
template <typename T>
150
167
class NonCopyable {
168
+ #ifndef DOXYGEN_ONLY
151
169
protected:
152
170
/* *
153
171
* Disallow construction of NonCopyable objects from outside of its hierarchy.
@@ -162,11 +180,11 @@ class NonCopyable {
162
180
/* *
163
181
* NonCopyable copy constructor.
164
182
*
165
- * A compile time warning is issued when this function is used and a runtime
166
- * warning is printed when the copy construction of the non copyable happens.
183
+ * A compile time warning is issued when this function is used, and a runtime
184
+ * warning is printed when the copy construction of the noncopyable happens.
167
185
*
168
186
* If you see this warning, your code is probably doing something unspecified.
169
- * Copy of non copyable resources can lead to resource leak and random error.
187
+ * Copying of noncopyable resources can lead to resource leak and random error.
170
188
*/
171
189
MBED_DEPRECATED (" Invalid copy construction of a NonCopyable resource." )
172
190
NonCopyable(const NonCopyable &)
@@ -177,11 +195,11 @@ class NonCopyable {
177
195
/* *
178
196
* NonCopyable copy assignment operator.
179
197
*
180
- * A compile time warning is issued when this function is used and a runtime
181
- * warning is printed when the copy construction of the non copyable happens.
198
+ * A compile time warning is issued when this function is used, and a runtime
199
+ * warning is printed when the copy construction of the noncopyable happens.
182
200
*
183
201
* If you see this warning, your code is probably doing something unspecified.
184
- * Copy of non copyable resources can lead to resource leak and random error.
202
+ * Copying of noncopyable resources can lead to resource leak and random error.
185
203
*/
186
204
MBED_DEPRECATED (" Invalid copy assignment of a NonCopyable resource." )
187
205
NonCopyable &operator=(const NonCopyable &)
@@ -193,19 +211,24 @@ class NonCopyable {
193
211
#else
194
212
private:
195
213
/* *
196
- * Declare copy constructor as private, any attempt to copy construct
214
+ * Declare copy constructor as private. Any attempt to copy construct
197
215
* a NonCopyable will fail at compile time.
198
216
*/
199
217
NonCopyable (const NonCopyable &);
200
218
201
219
/* *
202
- * Declare copy assignment operator as private, any attempt to copy assign
220
+ * Declare copy assignment operator as private. Any attempt to copy assign
203
221
* a NonCopyable will fail at compile time.
204
222
*/
205
223
NonCopyable &operator =(const NonCopyable &);
206
224
#endif
225
+ #endif
207
226
};
208
227
228
+ /* *@}*/
229
+
230
+ /* *@}*/
231
+
209
232
} // namespace mbed
210
233
211
234
#endif /* MBED_NONCOPYABLE_H_ */
0 commit comments