Mbed OS Reference
Loading...
Searching...
No Matches
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
20namespace mbed {
21
22/** \addtogroup platform-public-api */
23/** @{*/
24
25/**
26 * \defgroup platform_NonCopyable NonCopyable class
27 * @{
28 */
29
30/**
31 * Prevents generation of copy constructor and copy assignment operator in
32 * derived classes.
33 *
34 * @par Usage
35 *
36 * To prevent generation of copy constructor and copy assignment operator,
37 * inherit privately from the NonCopyable class.
38 *
39 * @code
40 * class Resource : NonCopyable<Resource> { };
41 *
42 * Resource r;
43 * // generates compile time error:
44 * Resource r2 = r;
45 * @endcode
46 *
47 * @par Background information
48 *
49 * Instances of polymorphic classes are not meant to be copied. The
50 * C++ standards generate a default copy constructor and copy assignment
51 * function if these functions have not been defined in the class.
52 *
53 * Consider the following example:
54 *
55 * @code
56 * // base class representing a connection
57 * struct Connection {
58 * Connection();
59 * virtual ~Connection();
60 * virtual void open() = 0;
61 * }
62 *
63 * class SerialConnection : public Connection {
64 * public:
65 * SerialConnection(Serial*);
66 *
67 * private:
68 * Serial* _serial;
69 * };
70 *
71 * Connection& get_connection() {
72 * static SerialConnection serial_connection;
73 * return serial_connection;
74 * }
75 *
76 * Connection connection = get_connection();
77 * @endcode
78 *
79 * There is a subtle bug in this code, the function get_connection returns a
80 * reference to a Connection which is captured by value instead of reference.
81 *
82 * When `get_connection` returns a reference to serial_connection it is copied into
83 * the local variable connection. The vtable and others members defined in Connection
84 * are copied, but members defined in SerialConnection are left apart. This can cause
85 * severe crashes or bugs if the virtual functions captured use members not present
86 * in the base declaration.
87 *
88 * To solve that problem, the copy constructor and assignment operator have to
89 * be defined as deleted:
90 *
91 * @code
92 * struct Connection {
93 * Connection(const Connection &) = delete;
94 * Connection &operator=(const Connection &) = delete;
95 * }
96 * @endcode
97 *
98 * Although manually defining deleted copy constructor and assignment functions
99 * works, it is not ideal. These declarations are usually easy to forget,
100 * not immediately visible, and may be obscure to uninformed programmers.
101 *
102 * Using the NonCopyable class reduces the boilerplate required and expresses
103 * the intent because class inheritance appears right after the class name
104 * declaration.
105 *
106 * @code
107 * struct Connection : private NonCopyable<Connection> {
108 * // regular declarations
109 * }
110 * @endcode
111 *
112 *
113 * @par Implementation details
114 *
115 * Using a template type prevents cases where the empty base optimization cannot
116 * be applied and therefore ensures that the cost of the NonCopyable semantic
117 * sugar is null.
118 *
119 * As an example, the empty base optimization is prohibited if one of the empty
120 * base classes is also a base type of the first nonstatic data member:
121 *
122 * @code
123 * struct A { };
124 * struct B : A {
125 * int foo;
126 * };
127 * // thanks to empty base optimization, sizeof(B) == sizeof(int)
128 *
129 * struct C : A {
130 * B b;
131 * };
132 *
133 * // empty base optimization cannot be applied here because A from C and A from
134 * // B have a different address. In that case, with the alignment
135 * // sizeof(C) == 2* sizeof(int)
136 * @endcode
137 *
138 * The solution to that problem is to templatize the empty class to make it
139 * unique to the type it is applied to:
140 *
141 * @code
142 * template<typename T>
143 * struct A<T> { };
144 * struct B : A<B> {
145 * int foo;
146 * };
147 * struct C : A<C> {
148 * B b;
149 * };
150 *
151 * // empty base optimization can be applied B and C does not refer to the same
152 * // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
153 * @endcode
154 *
155 * @tparam T The type that should be made noncopyable.
156 *
157 * @note Compile time errors are disabled if you use the develop or release profile.
158 * To override this behavior and force compile time errors in all profiles,
159 * set the configuration parameter "platform.force-non-copyable-error" to true.
160 */
161template<typename T>
163#ifndef DOXYGEN_ONLY
164protected:
165 /**
166 * Disallow construction of NonCopyable objects from outside of its hierarchy.
167 */
168 NonCopyable() = default;
169 /**
170 * Disallow destruction of NonCopyable objects from outside of its hierarchy.
171 */
172 ~NonCopyable() = default;
173
174public:
175 /**
176 * Define copy constructor as deleted. Any attempt to copy construct
177 * a NonCopyable will fail at compile time.
178 */
179 NonCopyable(const NonCopyable &) = delete;
180
181 /**
182 * Define copy assignment operator as deleted. Any attempt to copy assign
183 * a NonCopyable will fail at compile time.
184 */
185 NonCopyable &operator=(const NonCopyable &) = delete;
186#endif
187};
188
189/**@}*/
190
191/**@}*/
192
193} // namespace mbed
194
195#endif /* MBED_NONCOPYABLE_H_ */
Prevents generation of copy constructor and copy assignment operator in derived classes.
Definition: NonCopyable.h:162