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