Rtos API example

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 #if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
00020 #include "mbed_toolchain.h"
00021 #include "mbed_debug.h"
00022 #endif
00023 
00024 namespace mbed {
00025 
00026 /**
00027  * Inheriting from this class autogeneration of copy construction and copy
00028  * assignement operations.
00029  *
00030  * Classes which are not value type should inherit privately from this class
00031  * to avoid generation of invalid copy constructor or copy assignement operator
00032  * which can lead to unoticeable programming errors.
00033  *
00034  * As an example consider the following signature:
00035  *
00036  * @code
00037  * class Resource;
00038  *
00039  * class Foo {
00040  * public:
00041  *   Foo() : _resource(new Resource()) { }
00042  *   ~Foo() { delete _resource; }
00043  * private:
00044  *   Resource* _resource;
00045  * }
00046  *
00047  * Foo get_foo();
00048  *
00049  * Foo foo = get_foo();
00050  * @endcode
00051  *
00052  * There is a bug in this function, it returns a temporary value which will be
00053  * byte copied into foo then destroyed. Unfortunately, internaly the Foo class
00054  * manage a pointer to a Resource object. This pointer will be released when the
00055  * temporary is destroyed and foo will manage a pointer to an already released
00056  * Resource.
00057  *
00058  * Two issues has to be fixed in the example above:
00059  *   - Function signature has to be changed to reflect the fact that Foo
00060  *     instances cannot be copied. In that case accessor should return a
00061  *     reference to give access to objects already existing and managed.
00062  *     Generator on the other hand should return a pointer to the created object.
00063  *
00064  * @code
00065  * // return a reference to an already managed Foo instance
00066  * Foo& get_foo();
00067  * Foo& foo = get_foo();
00068  *
00069  * // create a new Foo instance
00070  * Foo* make_foo();
00071  * Foo* m = make_foo();
00072  * @endcode
00073  *
00074  *   - Copy constructor and copy assignement operator has to be made private
00075  *     in the Foo class. It prevents unwanted copy of Foo objects. This can be
00076  *     done by declaring copy constructor and copy assignement in the private
00077  *     section of the Foo class.
00078  *
00079  * @code
00080  * class Foo {
00081  * public:
00082  *   Foo() : _resource(new Resource()) { }
00083  *   ~Foo() { delete _resource; }
00084  * private:
00085  *   // disallow copy operations
00086  *   Foo(const Foo&);
00087  *   Foo& operator=(const Foo&);
00088  *   // data members
00089  *   Resource* _resource;
00090  * }
00091  * @endcode
00092  *
00093  * Another solution is to inherit privately from the NonCopyable class.
00094  * It reduces the boiler plate needed to avoid copy operations but more
00095  * importantly it clarifies the programer intent and the object semantic.
00096  *
00097  * class Foo : private NonCopyable<Foo> {
00098  * public:
00099  *   Foo() : _resource(new Resource()) { }
00100  *   ~Foo() { delete _resource; }
00101  * private:
00102  *   Resource* _resource;
00103  * }
00104  *
00105  * @tparam T The type that should be made non copyable. It prevent cases where
00106  * the empty base optimization cannot be applied and therefore ensure that the
00107  * cost of this semantic sugar is null.
00108  *
00109  * As an example, the empty base optimization is prohibited if one of the empty
00110  * base class is also a base type of the first non static data member:
00111  *
00112  * @code
00113  * struct A { };
00114  * struct B : A {
00115  *    int foo;
00116  * };
00117  * // thanks to empty base optimization, sizeof(B) == sizeof(int)
00118  *
00119  * struct C : A {
00120  *   B b;
00121  * };
00122  *
00123  * // empty base optimization cannot be applied here because A from C and A from
00124  * // B shall have a different address. In that case, with the alignement
00125  * // sizeof(C) == 2* sizeof(int)
00126  * @endcode
00127  *
00128  * The solution to that problem is to templatize the empty class to makes it
00129  * unique to the type it is applied to:
00130  *
00131  * @code
00132  * template<typename T>
00133  * struct A<T> { };
00134  * struct B : A<B> {
00135  *    int foo;
00136  * };
00137  * struct C : A<C> {
00138  *   B b;
00139  * };
00140  *
00141  * // empty base optimization can be applied B and C does not refer to the same
00142  * // kind of A. sizeof(C) == sizeof(B) == sizeof(int).
00143  * @endcode
00144  *
00145  * @note Compile time errors are disabled if the develop or the release profile
00146  * is used. To override this behavior and force compile time errors in all profile
00147  * set the configuration parameter "platform.force-non-copyable-error" to true.
00148  */
00149 template<typename T>
00150 class NonCopyable {
00151 protected:
00152     /**
00153      * Disalow construction of NonCopyable objects from outside of its hierarchy.
00154      */
00155     NonCopyable() { }
00156     /**
00157      * Disalow destruction of NonCopyable objects from outside of its hierarchy.
00158      */
00159     ~NonCopyable() { }
00160 
00161 #if (!defined(MBED_DEBUG) && (MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR == 0))
00162     /**
00163      * NonCopyable copy constructor.
00164      *
00165      * A compile time warning is issued when this function is used and a runtime
00166      * warning is printed when the copy construction of the non copyable happens.
00167      *
00168      * If you see this warning, your code is probably doing something unspecified.
00169      * Copy of non copyable resources can lead to resource leak and random error.
00170      */
00171     MBED_DEPRECATED("Invalid copy construction of a NonCopyable resource.")
00172     NonCopyable(const NonCopyable&)
00173     {
00174         debug("Invalid copy construction of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
00175     }
00176 
00177     /**
00178      * NonCopyable copy assignment operator.
00179      *
00180      * A compile time warning is issued when this function is used and a runtime
00181      * warning is printed when the copy construction of the non copyable happens.
00182      *
00183      * If you see this warning, your code is probably doing something unspecified.
00184      * Copy of non copyable resources can lead to resource leak and random error.
00185      */
00186     MBED_DEPRECATED("Invalid copy assignment of a NonCopyable resource.")
00187     NonCopyable& operator=(const NonCopyable&)
00188     {
00189         debug("Invalid copy assignment of a NonCopyable resource: %s\r\n", MBED_PRETTY_FUNCTION);
00190         return *this;
00191     }
00192 
00193 #else
00194 private:
00195     /**
00196      * Declare copy constructor as private, any attempt to copy construct
00197      * a NonCopyable will fail at compile time.
00198      */
00199     NonCopyable(const NonCopyable&);
00200 
00201     /**
00202      * Declare copy assignement operator as private, any attempt to copy assign
00203      * a NonCopyable will fail at compile time.
00204      */
00205     NonCopyable& operator=(const NonCopyable&);
00206 #endif
00207 };
00208 
00209 } // namespace mbed
00210 
00211 #endif /* MBED_NONCOPYABLE_H_ */