Skip to content

Commit 4198695

Browse files
authored
Merge pull request #5485 from pan-/non-copyable-warning
Platform: Allow copy of non copyable objects
2 parents 1fa09fa + 80c9f8b commit 4198695

File tree

3 files changed

+150
-88
lines changed

3 files changed

+150
-88
lines changed

platform/NonCopyable.h

Lines changed: 120 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -16,153 +16,196 @@
1616
#ifndef MBED_NONCOPYABLE_H_
1717
#define MBED_NONCOPYABLE_H_
1818

19-
namespace mbed {
19+
#if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
20+
#include "mbed_toolchain.h"
21+
#include "mbed_debug.h"
22+
#endif
23+
24+
namespace mbed {
2025

2126
/**
22-
* Inheriting from this class autogeneration of copy construction and copy
23-
* assignement operations.
24-
*
25-
* Classes which are not value type should inherit privately from this class
27+
* Inheriting from this class autogeneration of copy construction and copy
28+
* assignement operations.
29+
*
30+
* Classes which are not value type should inherit privately from this class
2631
* to avoid generation of invalid copy constructor or copy assignement operator
27-
* which can lead to unoticeable programming errors.
28-
*
29-
* As an example consider the following signature:
30-
*
32+
* which can lead to unoticeable programming errors.
33+
*
34+
* As an example consider the following signature:
35+
*
3136
* @code
32-
* class Resource;
37+
* class Resource;
3338
*
34-
* class Foo {
35-
* public:
39+
* class Foo {
40+
* public:
3641
* Foo() : _resource(new Resource()) { }
37-
* ~Foo() { delete _resource; }
42+
* ~Foo() { delete _resource; }
3843
* private:
3944
* Resource* _resource;
4045
* }
41-
*
46+
*
4247
* Foo get_foo();
43-
*
48+
*
4449
* Foo foo = get_foo();
45-
* @endcode
46-
*
47-
* There is a bug in this function, it returns a temporary value which will be
48-
* byte copied into foo then destroyed. Unfortunately, internaly the Foo class
49-
* manage a pointer to a Resource object. This pointer will be released when the
50-
* temporary is destroyed and foo will manage a pointer to an already released
50+
* @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, internaly 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
5156
* Resource.
52-
*
53-
* Two issues has to be fixed in the example above:
54-
* - Function signature has to be changed to reflect the fact that Foo
55-
* instances cannot be copied. In that case accessor should return a
56-
* reference to give access to objects already existing and managed.
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.
5762
* Generator on the other hand should return a pointer to the created object.
58-
*
59-
* @code
63+
*
64+
* @code
6065
* // return a reference to an already managed Foo instance
61-
* Foo& get_foo();
66+
* Foo& get_foo();
6267
* Foo& foo = get_foo();
63-
*
68+
*
6469
* // create a new Foo instance
6570
* Foo* make_foo();
6671
* Foo* m = make_foo();
6772
* @endcode
68-
*
69-
* - Copy constructor and copy assignement operator has to be made private
70-
* in the Foo class. It prevents unwanted copy of Foo objects. This can be
71-
* done by declaring copy constructor and copy assignement in the private
73+
*
74+
* - Copy constructor and copy assignement 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 assignement in the private
7277
* section of the Foo class.
73-
*
74-
* @code
75-
* class Foo {
76-
* public:
78+
*
79+
* @code
80+
* class Foo {
81+
* public:
7782
* Foo() : _resource(new Resource()) { }
78-
* ~Foo() { delete _resource; }
83+
* ~Foo() { delete _resource; }
7984
* private:
80-
* // disallow copy operations
85+
* // disallow copy operations
8186
* Foo(const Foo&);
8287
* Foo& operator=(const Foo&);
83-
* // data members
88+
* // data members
8489
* Resource* _resource;
8590
* }
8691
* @endcode
87-
*
88-
* Another solution is to inherit privately from the NonCopyable class.
89-
* It reduces the boiler plate needed to avoid copy operations but more
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
9095
* importantly it clarifies the programer intent and the object semantic.
9196
*
92-
* class Foo : private NonCopyable<Foo> {
93-
* public:
97+
* class Foo : private NonCopyable<Foo> {
98+
* public:
9499
* Foo() : _resource(new Resource()) { }
95-
* ~Foo() { delete _resource; }
100+
* ~Foo() { delete _resource; }
96101
* private:
97102
* Resource* _resource;
98103
* }
99-
*
100-
* @tparam T The type that should be made non copyable. It prevent cases where
101-
* the empty base optimization cannot be applied and therefore ensure that the
102-
* cost of this semantic sugar is null.
103-
*
104-
* As an example, the empty base optimization is prohibited if one of the empty
105-
* base class is also a base type of the first non static data member:
106-
*
107-
* @code
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+
*
109+
* 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:
111+
*
112+
* @code
108113
* struct A { };
109-
* struct B : A {
114+
* struct B : A {
110115
* int foo;
111116
* };
112117
* // thanks to empty base optimization, sizeof(B) == sizeof(int)
113-
*
114-
* struct C : A {
118+
*
119+
* struct C : A {
115120
* B b;
116121
* };
117-
*
122+
*
118123
* // empty base optimization cannot be applied here because A from C and A from
119-
* // B shall have a different address. In that case, with the alignement
124+
* // B shall have a different address. In that case, with the alignement
120125
* // sizeof(C) == 2* sizeof(int)
121126
* @endcode
122-
*
123-
* The solution to that problem is to templatize the empty class to makes it
124-
* unique to the type it is applied to:
125-
*
126-
* @code
127+
*
128+
* The solution to that problem is to templatize the empty class to makes it
129+
* unique to the type it is applied to:
130+
*
131+
* @code
127132
* template<typename T>
128133
* struct A<T> { };
129-
* struct B : A<B> {
134+
* struct B : A<B> {
130135
* int foo;
131136
* };
132-
* struct C : A<C> {
137+
* struct C : A<C> {
133138
* B b;
134139
* };
135-
*
136-
* // empty base optimization can be applied B and C does not refer to the same
140+
*
141+
* // empty base optimization can be applied B and C does not refer to the same
137142
* // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
138143
* @endcode
144+
*
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
147+
* set the configuration parameter "platform.force-non-copyable-error" to true.
139148
*/
140149
template<typename T>
141-
class NonCopyable {
150+
class NonCopyable {
142151
protected:
143-
/**
152+
/**
144153
* Disalow construction of NonCopyable objects from outside of its hierarchy.
145154
*/
146155
NonCopyable() { }
147-
/**
156+
/**
148157
* Disalow destruction of NonCopyable objects from outside of its hierarchy.
149158
*/
150159
~NonCopyable() { }
151160

152-
private:
161+
#if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
162+
/**
163+
* NonCopyable copy constructor.
164+
*
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.
167+
*
168+
* 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.
170+
*/
171+
MBED_DEPRECATED("Invalid copy construction of a NonCopyable resource.")
172+
NonCopyable(const NonCopyable&)
173+
{
174+
debug("Invalid copy construction of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
175+
}
176+
177+
/**
178+
* NonCopyable copy assignment operator.
179+
*
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.
182+
*
183+
* 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.
185+
*/
186+
MBED_DEPRECATED("Invalid copy assignment of a NonCopyable resource.")
187+
NonCopyable& operator=(const NonCopyable&)
188+
{
189+
debug("Invalid copy assignment of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
190+
return *this;
191+
}
192+
193+
#else
194+
private:
153195
/**
154-
* Declare copy constructor as private, any attempt to copy construct
196+
* Declare copy constructor as private, any attempt to copy construct
155197
* a NonCopyable will fail at compile time.
156198
*/
157199
NonCopyable(const NonCopyable&);
158200

159201
/**
160-
* Declare copy assignement operator as private, any attempt to copy assign
202+
* Declare copy assignement operator as private, any attempt to copy assign
161203
* a NonCopyable will fail at compile time.
162204
*/
163205
NonCopyable& operator=(const NonCopyable&);
206+
#endif
164207
};
165208

166-
} // namespace mbed
209+
} // namespace mbed
167210

168211
#endif /* MBED_NONCOPYABLE_H_ */

platform/mbed_lib.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
"default-serial-baud-rate": {
2020
"help": "Default baud rate for a Serial or RawSerial instance (if not specified in the constructor)",
2121
"value": 9600
22+
},
23+
24+
"force-non-copyable-error": {
25+
"help": "Force compile time error when a NonCopyable object is copied",
26+
"value": false
2227
}
2328
},
2429
"target_overrides": {

platform/mbed_toolchain.h

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* \defgroup platform_toolchain Toolchain functions
66
* @{
77
*/
8-
8+
99
/* mbed Microcontroller Library
1010
* Copyright (c) 2006-2013 ARM Limited
1111
*
@@ -63,7 +63,7 @@
6363
*
6464
* @note
6565
* IAR does not support alignment greater than word size on the stack
66-
*
66+
*
6767
* @code
6868
* #include "mbed_toolchain.h"
6969
*
@@ -125,16 +125,16 @@
125125
* should contain a regular function declaration to insure the function is emitted.
126126
* A function marked weak will not be emitted if an alternative non-weak
127127
* implementation is defined.
128-
*
128+
*
129129
* @note
130130
* Weak functions are not friendly to making code re-usable, as they can only
131131
* be overridden once (and if they are multiply overridden the linker will emit
132132
* no warning). You should not normally use weak symbols as part of the API to
133133
* re-usable modules.
134-
*
134+
*
135135
* @code
136136
* #include "mbed_toolchain.h"
137-
*
137+
*
138138
* MBED_WEAK void foo() {
139139
* // a weak implementation of foo that can be overriden by a definition
140140
* // without __weak
@@ -173,9 +173,9 @@
173173
*
174174
* @code
175175
* #include "mbed_toolchain.h"
176-
*
176+
*
177177
* MBED_NOINLINE void foo() {
178-
*
178+
*
179179
* }
180180
* @endcode
181181
*/
@@ -195,9 +195,9 @@
195195
*
196196
* @code
197197
* #include "mbed_toolchain.h"
198-
*
198+
*
199199
* MBED_FORCEINLINE void foo() {
200-
*
200+
*
201201
* }
202202
* @endcode
203203
*/
@@ -216,7 +216,7 @@
216216
*
217217
* @code
218218
* #include "mbed_toolchain.h"
219-
*
219+
*
220220
* MBED_NORETURN void foo() {
221221
* // must never return
222222
* while (1) {}
@@ -266,7 +266,7 @@
266266
*
267267
* @code
268268
* #include "mbed_toolchain.h"
269-
*
269+
*
270270
* MBED_DEPRECATED("don't foo any more, bar instead")
271271
* void foo(int arg);
272272
* @endcode
@@ -330,6 +330,20 @@
330330
#endif
331331
#endif
332332

333+
/**
334+
* Macro expanding to a string literal of the enclosing function name.
335+
*
336+
* The string returned takes into account language specificity and yield human
337+
* readable content.
338+
*
339+
* As an example, if the macro is used within a C++ function then the string
340+
* literal containing the function name will contain the complete signature of
341+
* the function - including template parameters - and namespace qualifications.
342+
*/
343+
#ifndef MBED_PRETTY_FUNCTION
344+
#define MBED_PRETTY_FUNCTION __PRETTY_FUNCTION__
345+
#endif
346+
333347
#ifndef MBED_PRINTF
334348
#if defined(__GNUC__) || defined(__CC_ARM)
335349
#define MBED_PRINTF(format_idx, first_param_idx) __attribute__ ((__format__(__printf__, format_idx, first_param_idx)))

0 commit comments

Comments
 (0)