Skip to content

Commit 99e198a

Browse files
Cruz Monrreal IICruz Monrreal II
authored andcommitted
Merge branch 'non-copyable-doc' of ssh://github.com/pan-/mbed into rollup
2 parents b364dcb + 47adbd2 commit 99e198a

File tree

1 file changed

+107
-84
lines changed

1 file changed

+107
-84
lines changed

platform/NonCopyable.h

Lines changed: 107 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -23,91 +23,106 @@
2323

2424
namespace mbed {
2525

26+
/** \addtogroup platform */
27+
/** @{*/
2628
/**
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+
*
3658
* @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 {
4067
* public:
41-
* Foo() : _resource(new Resource()) { }
42-
* ~Foo() { delete _resource; }
68+
* SerialConnection(Serial*);
69+
*
4370
* private:
44-
* Resource* _resource;
71+
* Serial* _serial;
72+
* };
73+
*
74+
* Connection& get_connection() {
75+
* static SerialConnection serial_connection;
76+
* return serial_connection;
4577
* }
4678
*
47-
* Foo get_foo();
48-
*
49-
* Foo foo = get_foo();
79+
* Connection connection = get_connection();
5080
* @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+
*
6495
* @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 {
8497
* 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&);
90100
* }
91101
* @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
103114
* }
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+
*
109124
* 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:
111126
*
112127
* @code
113128
* struct A { };
@@ -121,11 +136,11 @@ namespace mbed {
121136
* };
122137
*
123138
* // 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
125140
* // sizeof(C) == 2* sizeof(int)
126141
* @endcode
127142
*
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
129144
* unique to the type it is applied to:
130145
*
131146
* @code
@@ -142,12 +157,15 @@ namespace mbed {
142157
* // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
143158
* @endcode
144159
*
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,
147164
* set the configuration parameter "platform.force-non-copyable-error" to true.
148165
*/
149166
template<typename T>
150167
class NonCopyable {
168+
#ifndef DOXYGEN_ONLY
151169
protected:
152170
/**
153171
* Disallow construction of NonCopyable objects from outside of its hierarchy.
@@ -162,11 +180,11 @@ class NonCopyable {
162180
/**
163181
* NonCopyable copy constructor.
164182
*
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.
167185
*
168186
* 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.
170188
*/
171189
MBED_DEPRECATED("Invalid copy construction of a NonCopyable resource.")
172190
NonCopyable(const NonCopyable &)
@@ -177,11 +195,11 @@ class NonCopyable {
177195
/**
178196
* NonCopyable copy assignment operator.
179197
*
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.
182200
*
183201
* 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.
185203
*/
186204
MBED_DEPRECATED("Invalid copy assignment of a NonCopyable resource.")
187205
NonCopyable &operator=(const NonCopyable &)
@@ -193,19 +211,24 @@ class NonCopyable {
193211
#else
194212
private:
195213
/**
196-
* Declare copy constructor as private, any attempt to copy construct
214+
* Declare copy constructor as private. Any attempt to copy construct
197215
* a NonCopyable will fail at compile time.
198216
*/
199217
NonCopyable(const NonCopyable &);
200218

201219
/**
202-
* Declare copy assignment operator as private, any attempt to copy assign
220+
* Declare copy assignment operator as private. Any attempt to copy assign
203221
* a NonCopyable will fail at compile time.
204222
*/
205223
NonCopyable &operator=(const NonCopyable &);
206224
#endif
225+
#endif
207226
};
208227

228+
/**@}*/
229+
230+
/**@}*/
231+
209232
} // namespace mbed
210233

211234
#endif /* MBED_NONCOPYABLE_H_ */

0 commit comments

Comments
 (0)