forked
Embed:
(wiki syntax)
Show/hide line numbers
NonCopyable.h
00001 /* Copyright (c) 2017 ARM Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #ifndef MBED_NONCOPYABLE_H_ 00017 #define MBED_NONCOPYABLE_H_ 00018 00019 namespace mbed { 00020 00021 /** 00022 * Inheriting from this class autogeneration of copy construction and copy 00023 * assignement operations. 00024 * 00025 * Classes which are not value type should inherit privately from this class 00026 * to avoid generation of invalid copy constructor or copy assignement operator 00027 * which can lead to unoticeable programming errors. 00028 * 00029 * As an example consider the following signature: 00030 * 00031 * @code 00032 * class Resource; 00033 * 00034 * class Foo { 00035 * public: 00036 * Foo() : _resource(new Resource()) { } 00037 * ~Foo() { delete _resource; } 00038 * private: 00039 * Resource* _resource; 00040 * } 00041 * 00042 * Foo get_foo(); 00043 * 00044 * Foo foo = get_foo(); 00045 * @endcode 00046 * 00047 * There is a bug in this function, it returns a temporary value which will be 00048 * byte copied into foo then destroyed. Unfortunately, internaly the Foo class 00049 * manage a pointer to a Resource object. This pointer will be released when the 00050 * temporary is destroyed and foo will manage a pointer to an already released 00051 * Resource. 00052 * 00053 * Two issues has to be fixed in the example above: 00054 * - Function signature has to be changed to reflect the fact that Foo 00055 * instances cannot be copied. In that case accessor should return a 00056 * reference to give access to objects already existing and managed. 00057 * Generator on the other hand should return a pointer to the created object. 00058 * 00059 * @code 00060 * // return a reference to an already managed Foo instance 00061 * Foo& get_foo(); 00062 * Foo& foo = get_foo(); 00063 * 00064 * // create a new Foo instance 00065 * Foo* make_foo(); 00066 * Foo* m = make_foo(); 00067 * @endcode 00068 * 00069 * - Copy constructor and copy assignement operator has to be made private 00070 * in the Foo class. It prevents unwanted copy of Foo objects. This can be 00071 * done by declaring copy constructor and copy assignement in the private 00072 * section of the Foo class. 00073 * 00074 * @code 00075 * class Foo { 00076 * public: 00077 * Foo() : _resource(new Resource()) { } 00078 * ~Foo() { delete _resource; } 00079 * private: 00080 * // disallow copy operations 00081 * Foo(const Foo&); 00082 * Foo& operator=(const Foo&); 00083 * // data members 00084 * Resource* _resource; 00085 * } 00086 * @endcode 00087 * 00088 * Another solution is to inherit privately from the NonCopyable class. 00089 * It reduces the boiler plate needed to avoid copy operations but more 00090 * importantly it clarifies the programer intent and the object semantic. 00091 * 00092 * class Foo : private NonCopyable<Foo> { 00093 * public: 00094 * Foo() : _resource(new Resource()) { } 00095 * ~Foo() { delete _resource; } 00096 * private: 00097 * Resource* _resource; 00098 * } 00099 * 00100 * @tparam T The type that should be made non copyable. It prevent cases where 00101 * the empty base optimization cannot be applied and therefore ensure that the 00102 * cost of this semantic sugar is null. 00103 * 00104 * As an example, the empty base optimization is prohibited if one of the empty 00105 * base class is also a base type of the first non static data member: 00106 * 00107 * @code 00108 * struct A { }; 00109 * struct B : A { 00110 * int foo; 00111 * }; 00112 * // thanks to empty base optimization, sizeof(B) == sizeof(int) 00113 * 00114 * struct C : A { 00115 * B b; 00116 * }; 00117 * 00118 * // empty base optimization cannot be applied here because A from C and A from 00119 * // B shall have a different address. In that case, with the alignement 00120 * // sizeof(C) == 2* sizeof(int) 00121 * @endcode 00122 * 00123 * The solution to that problem is to templatize the empty class to makes it 00124 * unique to the type it is applied to: 00125 * 00126 * @code 00127 * template<typename T> 00128 * struct A<T> { }; 00129 * struct B : A<B> { 00130 * int foo; 00131 * }; 00132 * struct C : A<C> { 00133 * B b; 00134 * }; 00135 * 00136 * // empty base optimization can be applied B and C does not refer to the same 00137 * // kind of A. sizeof(C) == sizeof(B) == sizeof(int). 00138 * @endcode 00139 */ 00140 template<typename T> 00141 class NonCopyable { 00142 protected: 00143 /** 00144 * Disalow construction of NonCopyable objects from outside of its hierarchy. 00145 */ 00146 NonCopyable() { } 00147 /** 00148 * Disalow destruction of NonCopyable objects from outside of its hierarchy. 00149 */ 00150 ~NonCopyable() { } 00151 00152 private: 00153 /** 00154 * Declare copy constructor as private, any attempt to copy construct 00155 * a NonCopyable will fail at compile time. 00156 */ 00157 NonCopyable(const NonCopyable&); 00158 00159 /** 00160 * Declare copy assignement operator as private, any attempt to copy assign 00161 * a NonCopyable will fail at compile time. 00162 */ 00163 NonCopyable& operator=(const NonCopyable&); 00164 }; 00165 00166 } // namespace mbed 00167 00168 #endif /* MBED_NONCOPYABLE_H_ */
Generated on Tue Jul 12 2022 16:02:32 by 1.7.2