Skip to content

Commit 4f79438

Browse files
committed
platform: Add NonCopyable class.
The NonCopyable template class avoid autogeneration of copy assignement and copy construction function for classes inheriting from it.
1 parent c08864b commit 4f79438

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

platform/NonCopyable.h

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/* Copyright (c) 2017 ARM Limited
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#ifndef MBED_NONCOPYABLE_H_
17+
#define MBED_NONCOPYABLE_H_
18+
19+
namespace mbed {
20+
21+
/**
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
26+
* 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+
*
31+
* @code
32+
* class Resource;
33+
*
34+
* class Foo {
35+
* public:
36+
* Foo() : _resource(new Resource()) { }
37+
* ~Foo() { delete _resource; }
38+
* private:
39+
* Resource* _resource;
40+
* }
41+
*
42+
* Foo get_foo();
43+
*
44+
* 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
51+
* 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+
* Generator on the other hand should return a pointer to the created object.
58+
*
59+
* @code
60+
* // return a reference to an already managed Foo instance
61+
* Foo& get_foo();
62+
* Foo& foo = get_foo();
63+
*
64+
* // create a new Foo instance
65+
* Foo* make_foo();
66+
* Foo* m = make_foo();
67+
* @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
72+
* section of the Foo class.
73+
*
74+
* @code
75+
* class Foo {
76+
* public:
77+
* Foo() : _resource(new Resource()) { }
78+
* ~Foo() { delete _resource; }
79+
* private:
80+
* // disallow copy operations
81+
* Foo(const Foo&);
82+
* Foo& operator=(const Foo&);
83+
* // data members
84+
* Resource* _resource;
85+
* }
86+
* @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
90+
* importantly it clarifies the programer intent and the object semantic.
91+
*
92+
* class Foo : private NonCopyable<Foo> {
93+
* public:
94+
* Foo() : _resource(new Resource()) { }
95+
* ~Foo() { delete _resource; }
96+
* private:
97+
* Resource* _resource;
98+
* }
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
108+
* struct A { };
109+
* struct B : A {
110+
* int foo;
111+
* };
112+
* // thanks to empty base optimization, sizeof(B) == sizeof(int)
113+
*
114+
* struct C : A {
115+
* B b;
116+
* };
117+
*
118+
* // 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
120+
* // sizeof(C) == 2* sizeof(int)
121+
* @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+
* template<typename T>
128+
* struct A<T> { };
129+
* struct B : A<B> {
130+
* int foo;
131+
* };
132+
* struct C : A<C> {
133+
* B b;
134+
* };
135+
*
136+
* // empty base optimization can be applied B and C does not refer to the same
137+
* // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
138+
* @endcode
139+
*/
140+
template<typename T>
141+
class NonCopyable {
142+
protected:
143+
/**
144+
* Disalow construction of NonCopyable objects from outside of its hierarchy.
145+
*/
146+
NonCopyable() { }
147+
/**
148+
* Disalow destruction of NonCopyable objects from outside of its hierarchy.
149+
*/
150+
~NonCopyable() { }
151+
152+
private:
153+
/**
154+
* Declare copy constructor as private, any attempt to copy construct
155+
* a NonCopyable will fail at compile time.
156+
*/
157+
NonCopyable(const NonCopyable&);
158+
159+
/**
160+
* Declare copy assignement operator as private, any attempt to copy assign
161+
* a NonCopyable will fail at compile time.
162+
*/
163+
NonCopyable& operator=(const NonCopyable&);
164+
};
165+
166+
} // namespace mbed
167+
168+
#endif /* MBED_NONCOPYABLE_H_ */

0 commit comments

Comments
 (0)