forked

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NonCopyable.h Source File

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_ */