Mistake on this page?
Report an issue in GitHub or email us
NonCopyable.h
1 /* Copyright (c) 2017 ARM Limited
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MBED_NONCOPYABLE_H_
18 #define MBED_NONCOPYABLE_H_
19 
20 #if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
21 #include "mbed_toolchain.h"
22 #include "mbed_debug.h"
23 #endif
24 
25 namespace mbed {
26 
27 /** \addtogroup platform */
28 /** @{*/
29 /**
30  * \defgroup platform_NonCopyable NonCopyable class
31  * @{
32  */
33 
34 /**
35  * Prevents generation of copy constructor and copy assignment operator in
36  * derived classes.
37  *
38  * @par Usage
39  *
40  * To prevent generation of copy constructor and copy assignment operator,
41  * inherit privately from the NonCopyable class.
42  *
43  * @code
44  * class Resource : NonCopyable<Resource> { };
45  *
46  * Resource r;
47  * // generates compile time error:
48  * Resource r2 = r;
49  * @endcode
50  *
51  * @par Background information
52  *
53  * Instances of polymorphic classes are not meant to be copied. The
54  * C++ standards generate a default copy constructor and copy assignment
55  * function if these functions have not been defined in the class.
56  *
57  * Consider the following example:
58  *
59  * @code
60  * // base class representing a connection
61  * struct Connection {
62  * Connection();
63  * virtual ~Connection();
64  * virtual void open() = 0;
65  * }
66  *
67  * class SerialConnection : public Connection {
68  * public:
69  * SerialConnection(Serial*);
70  *
71  * private:
72  * Serial* _serial;
73  * };
74  *
75  * Connection& get_connection() {
76  * static SerialConnection serial_connection;
77  * return serial_connection;
78  * }
79  *
80  * Connection connection = get_connection();
81  * @endcode
82  *
83  * There is a subtle bug in this code, the function get_connection returns a
84  * reference to a Connection which is captured by value instead of reference.
85  *
86  * When `get_connection` returns a reference to serial_connection it is copied into
87  * the local variable connection. The vtable and others members defined in Connection
88  * are copied, but members defined in SerialConnection are left apart. This can cause
89  * severe crashes or bugs if the virtual functions captured use members not present
90  * in the base declaration.
91  *
92  * To solve that problem, the copy constructor and assignment operator have to
93  * be declared (but don't need to be defined) in the private section of the
94  * Connection class:
95  *
96  * @code
97  * struct Connection {
98  * private:
99  * Connection(const Connection&);
100  * Connection& operator=(const Connection&);
101  * }
102  * @endcode
103  *
104  * Although manually declaring private copy constructor and assignment functions
105  * works, it is not ideal. These declarations are usually easy to forget,
106  * not immediately visible, and may be obscure to uninformed programmers.
107  *
108  * Using the NonCopyable class reduces the boilerplate required and expresses
109  * the intent because class inheritance appears right after the class name
110  * declaration.
111  *
112  * @code
113  * struct Connection : private NonCopyable<Connection> {
114  * // regular declarations
115  * }
116  * @endcode
117  *
118  *
119  * @par Implementation details
120  *
121  * Using a template type prevents cases where the empty base optimization cannot
122  * be applied and therefore ensures that the cost of the NonCopyable semantic
123  * sugar is null.
124  *
125  * As an example, the empty base optimization is prohibited if one of the empty
126  * base classes is also a base type of the first nonstatic data member:
127  *
128  * @code
129  * struct A { };
130  * struct B : A {
131  * int foo;
132  * };
133  * // thanks to empty base optimization, sizeof(B) == sizeof(int)
134  *
135  * struct C : A {
136  * B b;
137  * };
138  *
139  * // empty base optimization cannot be applied here because A from C and A from
140  * // B have a different address. In that case, with the alignment
141  * // sizeof(C) == 2* sizeof(int)
142  * @endcode
143  *
144  * The solution to that problem is to templatize the empty class to make it
145  * unique to the type it is applied to:
146  *
147  * @code
148  * template<typename T>
149  * struct A<T> { };
150  * struct B : A<B> {
151  * int foo;
152  * };
153  * struct C : A<C> {
154  * B b;
155  * };
156  *
157  * // empty base optimization can be applied B and C does not refer to the same
158  * // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
159  * @endcode
160  *
161  * @tparam T The type that should be made noncopyable.
162  *
163  * @note Compile time errors are disabled if you use the develop or release profile.
164  * To override this behavior and force compile time errors in all profiles,
165  * set the configuration parameter "platform.force-non-copyable-error" to true.
166  */
167 template<typename T>
168 class NonCopyable {
169 #ifndef DOXYGEN_ONLY
170 protected:
171  /**
172  * Disallow construction of NonCopyable objects from outside of its hierarchy.
173  */
174  NonCopyable() { }
175  /**
176  * Disallow destruction of NonCopyable objects from outside of its hierarchy.
177  */
178  ~NonCopyable() { }
179 
180 #if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
181  /**
182  * NonCopyable copy constructor.
183  *
184  * A compile time warning is issued when this function is used, and a runtime
185  * warning is printed when the copy construction of the noncopyable happens.
186  *
187  * If you see this warning, your code is probably doing something unspecified.
188  * Copying of noncopyable resources can lead to resource leak and random error.
189  */
190  MBED_DEPRECATED("Invalid copy construction of a NonCopyable resource.")
191  NonCopyable(const NonCopyable &)
192  {
193  debug("Invalid copy construction of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
194  }
195 
196  /**
197  * NonCopyable copy assignment operator.
198  *
199  * A compile time warning is issued when this function is used, and a runtime
200  * warning is printed when the copy construction of the noncopyable happens.
201  *
202  * If you see this warning, your code is probably doing something unspecified.
203  * Copying of noncopyable resources can lead to resource leak and random error.
204  */
205  MBED_DEPRECATED("Invalid copy assignment of a NonCopyable resource.")
206  NonCopyable &operator=(const NonCopyable &)
207  {
208  debug("Invalid copy assignment of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
209  return *this;
210  }
211 
212 #else
213 private:
214  /**
215  * Declare copy constructor as private. Any attempt to copy construct
216  * a NonCopyable will fail at compile time.
217  */
218  NonCopyable(const NonCopyable &);
219 
220  /**
221  * Declare copy assignment operator as private. Any attempt to copy assign
222  * a NonCopyable will fail at compile time.
223  */
224  NonCopyable &operator=(const NonCopyable &);
225 #endif
226 #endif
227 };
228 
229 /**@}*/
230 
231 /**@}*/
232 
233 } // namespace mbed
234 
235 #endif /* MBED_NONCOPYABLE_H_ */
Prevents generation of copy constructor and copy assignment operator in derived classes.
Definition: NonCopyable.h:168
#define MBED_PRETTY_FUNCTION
Macro expanding to a string literal of the enclosing function name.
static void debug(const char *format,...)
Output a debug message.
Definition: mbed_debug.h:44
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.