Skip to content
This repository has been archived by the owner on Jun 26, 2019. It is now read-only.

Commit

Permalink
Merge pull request #53 from rleigh-codelibre/basic-c++11
Browse files Browse the repository at this point in the history
Basic C++11 features
  • Loading branch information
sbesson committed Feb 8, 2017
2 parents 8b4df13 + 36c7824 commit e5a4d5c
Show file tree
Hide file tree
Showing 75 changed files with 1,267 additions and 1,451 deletions.
23 changes: 0 additions & 23 deletions docs/sphinx/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@ project-specific options detailed below. Run ``cmake -LH`` to see the
configurable project options; use ``-LAH`` to see advanced options.
The following basic options are supported:

cxxstd-autodetect=(ON|OFF)
Enable or disable (default) C++ compiler standard autodetection. If
enabled, the compiler will be put into C++11 mode if available,
otherwise falling back to C++03 or C++98. If disabled, the default
compiler standard mode is used, and it is the responsibility of the
user to add the appropriate compiler options to build using the
required standard. This is useful if autodetection fails or a
compiler is buggy in certain modes (e.g. GCC 4.4 or 4.6 require
``-std=gnu++98`` or else ``stdarg`` support is broken).
doxygen=(ON|OFF)
Enable doxygen documentation. These will be enabled by default if
doxygen is found.
Expand Down Expand Up @@ -54,17 +45,3 @@ sphinx-linkcheck=(ON|OFF)
automatically, but may still be run by hand.
test=(ON|OFF)
Enable unit tests. Tests are enabled by default.

C++11
^^^^^

C++11 features such as :cpp:class:`std::shared_ptr` are used when
using a C++11 or C++14 compiler, or when ``-Dcxxstd-autodetect=ON`` is
used and the compiler can be put into a C++11 or C++14 compatibility
mode. When using an older compatbility mode such as C++98, the Boost
equivalents of C++11 library features will be used as fallbacks to
provide the same functionality. In both cases these types are
imported into the :cpp:class:`ome::compat` namespace, for example as
:cpp:class:`ome::compat::shared_ptr`, and the types in this namespace
should be used for portability when using any part of the API which
use types from this namespace.
148 changes: 67 additions & 81 deletions docs/sphinx/conversion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,17 @@ OME-Files API **never** passes pointers allocated with ``new``, nor
requires any manual memory management. Instead, “smart” pointers are
used throughout to manage memory safely and automatically.

:cpp:class:`ome::compat::shared_ptr` as a “smart” pointer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:cpp:class:`std::shared_ptr` as a “smart” pointer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The unsafe example above, has been rewritten to use
:cpp:class:`ome::compat::shared_ptr`:
:cpp:class:`std::shared_ptr`:

.. code-block:: cpp
// Start of block
{
ome::compat::shared_ptr<Image> i(ome::compat::make_shared<Image>(filename));
std::shared_ptr<Image> i(std::make_shared<Image>(filename));
i->read_plane(); // throws exception
Expand All @@ -284,20 +284,13 @@ The unsafe example above, has been rewritten to use
}
Rather than managing the memory by hand, responsibility for this is
delegated to a “smart” pointer, :cpp:class:`ome::compat::shared_ptr`.
The memory is freed by the :cpp:class:`ome::compat::shared_ptr`
destructor which is run at the end of the block scope, on explicit
:c:type:`return`, or when cleaned up by exception stack unwinding.

.. note::

:cpp:class:`ome::compat::shared_ptr` is either a
:cpp:class:`std::shared_ptr` or a :cpp:class:`boost::shared_ptr`,
depending upon whether C++11 features are avaiable or not,
respectively.
delegated to a “smart” pointer, :cpp:class:`std::shared_ptr`. The
memory is freed by the :cpp:class:`std::shared_ptr` destructor which
is run at the end of the block scope, on explicit :c:type:`return`, or
when cleaned up by exception stack unwinding.

- :cpp:class:`shared_ptr` object lifetime manages the resource
- ``new`` replaced with :cpp:class:`ome::compat::make_shared`
- ``new`` replaced with :cpp:class:`std::make_shared`
- May be used as class members; lifetime is tied to class instance
- Clean up for all exit points is automatic and safe
- Allows ownership transfer and sharing
Expand Down Expand Up @@ -339,29 +332,29 @@ C++ reference variants
.. code-block:: cpp
// Non-constant Constant
// ------------------------------------- ----------------------------------------------
// ----------------------------- --------------------------------------
// Pointer
Image *i; const Image *i;
Image * const i; const Image * const i;
Image *i; const Image *i;
Image * const i; const Image * const i;
// Reference
Image& i; const Image& i;
Image& i; const Image& i;
// Shared pointer
ome::compat::shared_ptr<Image> i; ome::compat::shared_ptr<const Image> i;
const ome::compat::shared_ptr<Image> i; const ome::compat::shared_ptr<const Image> i;
std::shared_ptr<Image> i; std::shared_ptr<const Image> i;
const std::shared_ptr<Image> i; const std::shared_ptr<const Image> i;
// Shared pointer reference
ome::compat::shared_ptr<Image>& i; ome::compat::shared_ptr<const Image>& i;
const ome::compat::shared_ptr<Image>& i; const ome::compat::shared_ptr<const Image>& i;
std::shared_ptr<Image>& i; std::shared_ptr<const Image>& i;
const std::shared_ptr<Image>& i; const std::shared_ptr<const Image>& i;
// Weak pointer
ome::compat::weak_ptr<Image> i; ome::compat::weak_ptr<const Image> i;
const ome::compat::weak_ptr<Image> i; const ome::compat::weak_ptr<const Image> i;
std::weak_ptr<Image> i; std::weak_ptr<const Image> i;
const std::weak_ptr<Image> i; const std::weak_ptr<const Image> i;
// Weak pointer reference
ome::compat::weak_ptr<Image>& i; ome::compat::weak_ptr<const Image>& i;
const ome::compat::weak_ptr<Image>& i; const ome::compat::weak_ptr<const Image>& i;
std::weak_ptr<Image>& i; std::weak_ptr<const Image>& i;
const std::weak_ptr<Image>& i; const std::weak_ptr<const Image>& i;
Java has one reference type. Here, we have **22**. Clearly, not all
of these will typically be used. Below, a subset of these are shown
Expand All @@ -371,24 +364,23 @@ Class member types:

.. code-block:: cpp
Image i; // Concrete instance
ome::compat::shared_ptr<Image> i; // Reference
ome::compat::weak_ptr<Image> i; // Weak reference
Image i; // Concrete instance
std::shared_ptr<Image> i; // Reference
std::weak_ptr<Image> i; // Weak reference
Wherever possible, a concrete instance should be preferred. This is
not possible for polymorphic types, where a reference is required. In
this situation, an :cpp:class:`ome::compat::shared_ptr` is preferred
if the class owns the member and/or needs control over its lifetime.
If the class does not have ownership then an
:cpp:class:`ome::compat::weak_ptr` will allow safe access to the
object if it still exists. In circumstances where manual lifetime
management is required, e.g. for performance, and the member is
guaranteed to exist for the duration of the object's lifetime, a plain
pointer or reference may be used. A pointer will be used if it is
possible for it to be :cpp:class:`null`, or it may be reassigned more
than once, or if is assigned after initial construction. If properly
using RAII, using references should be possible and preferred over
bare pointers in all cases.
this situation, an :cpp:class:`std::shared_ptr` is preferred if the
class owns the member and/or needs control over its lifetime. If the
class does not have ownership then an :cpp:class:`std::weak_ptr` will
allow safe access to the object if it still exists. In circumstances
where manual lifetime management is required, e.g. for performance,
and the member is guaranteed to exist for the duration of the object's
lifetime, a plain pointer or reference may be used. A pointer will be
used if it is possible for it to be :cpp:class:`null`, or it may be
reassigned more than once, or if is assigned after initial
construction. If properly using RAII, using references should be
possible and preferred over bare pointers in all cases.

Argument types:

Expand All @@ -397,7 +389,7 @@ Argument types:
// Ownership retained
void read_plane(const Image& image);
// Ownership shared or transferred
void read_plane(const ome::compat::shared_ptr<Image>& image);
void read_plane(const std::shared_ptr<Image>& image);
Passing primitive types by value is acceptable. However, passing a
struct or class by value will implicitly copy the object into the
Expand All @@ -407,12 +399,12 @@ polymorphic types). Passing by reference avoids the need for any
copying, and passing by :c:type:`const` reference will prevent the
callee from modifying the object, also making it clear that there is
no transfer of ownership. Passing using an
:cpp:class:`ome::compat::shared_ptr` is possible but not
recommended---the copy will involve reference counting overhead which
can kill multi-threaded performance since it requires synchronization
between all threads; use a :c:type:`const` reference to an
:cpp:class:`ome::compat::shared_ptr` to avoid the overhead. If
ownership should be transferred or shared with the callee, use a
:cpp:class:`std::shared_ptr` is possible but not recommended---the
copy will involve reference counting overhead which can kill
multi-threaded performance since it requires synchronization between
all threads; use a :c:type:`const` reference to an
:cpp:class:`std::shared_ptr` to avoid the overhead. If ownership
should be transferred or shared with the callee, use a
non-:c:type:`const` reference.

To be absolutely clear, plain pointers are never used and are not
Expand All @@ -423,10 +415,9 @@ Return types:

.. code-block:: cpp
Image get_image(); // Ownership transferred
Image& get_image(); // Ownership retained
ome::compat::shared_ptr<Image> get_image(); // Ownership shared/trans
ome::compat::shared_ptr<Image>& get_image(); // Ownership shared
Image get_image(); // Ownership transferred
Image& get_image(); // Ownership retained
std::shared_ptr<Image> get_image(); // Ownership shared/trans
If the callee does not retain a copy of the original object, it can't
pass by reference since it can't guarantee the object remaining in
Expand All @@ -435,10 +426,10 @@ pass by value. If the callee does retain a copy, it has the option of
passing by reference. Passing by reference is preferred when
possible. Passing by value implies ownership transfer. Passing by
reference implies ownership retention. Passing an
:cpp:class:`ome::compat::shared_ptr` by value or reference implies
sharing ownership since the caller can retain a reference; if passing
by value ownership *may* be transferred since this implies the callee
is not retaining a reference to it (but this is not guaranteed).
:cpp:class:`std::shared_ptr` by value or reference implies sharing
ownership since the caller can retain a reference; if passing by value
ownership *may* be transferred since this implies the callee is not
retaining a reference to it (but this is not guaranteed).

Again, to be absolutely clear, plain pointers are never used and are
not acceptable for ownership transfer. A plain reference also makes
Expand Down Expand Up @@ -477,26 +468,22 @@ is not known unless passed separately.
};
C++ arrays “decay” to “bare” pointers, and pointers have no associated
size information.

:cpp:class:`ome::compat::array` is a safe alternative. This is either
a C++11 :cpp:class:`std::array` or :cpp:class:`boost::array` with
older compilers.
size information. :cpp:class:`std::array` is a safe alternative.

.. code-block:: cpp
class Image
{
typedef ome::compat::array<uint8_t, 256> LUT;
typedef std::array<uint8_t, 256> LUT;
// Safe; size defined
const LUT& getLUT() const;
void setLUT(const LUT&);
};
:cpp:class:`ome::compat::array` is a array-like object (a class which
behaves like an array). Its type and size are defined in the
template, and it may be passed around like any other object. Its
:cpp:class:`std::array` is a array-like object (a class which behaves
like an array). Its type and size are defined in the template, and it
may be passed around like any other object. Its
:cpp:func:`array::at()` method provides strict bounds checking, while
its index :cpp:func:`array::operator[]` provides unchecked access.

Expand All @@ -508,15 +495,14 @@ Types with a common base

.. code-block:: cpp
std::vector<ome::compat::shared_ptr<Base> > v;
v.push_back(ome::compat::make_shared<Derived>());
std::vector<std::shared_ptr<Base>> v;
v.push_back(std::make_shared<Derived>());
This can store any type derived from :cpp:class:`Base`. An
:cpp:class:`ome::compat::shared_ptr` is **essential**. Without it,
bare pointers to the base would be stored, and memory would be leaked
when elements are removed from the container (unless externally
managed [generally unsafe]). The same applies to passing polymorphic
types.
:cpp:class:`std::shared_ptr` is **essential**. Without it, bare
pointers to the base would be stored, and memory would be leaked when
elements are removed from the container (unless externally managed
[generally unsafe]). The same applies to passing polymorphic types.

Java containers can be problematic:

Expand Down Expand Up @@ -576,8 +562,8 @@ code to operate on all of the supported types. The variant type may
be used as a class member, passed by value, passed by reference or
stored in a container like any other type. Due to the way it is
implemented to store values, it does not necessarily need wrapping in
an :cpp:class:`ome::compat::shared_ptr` since it can behave as a value
type (depending upon the context).
an :cpp:class:`std::shared_ptr` since it can behave as a value type
(depending upon the context).


Java uses polymorphism to store and pass the root :cpp:class:`Object`
Expand Down Expand Up @@ -764,7 +750,7 @@ integer, floating point, complex floating point and bitmask cases.
struct TypeCategoryVisitor : public boost::static_visitor<>
{
typedef ::ome::files::PixelProperties< ::ome::xml::model::enums::PixelType::BIT>::std_type bit_type;
typedef ::ome::files::PixelProperties<::ome::xml::model::enums::PixelType::BIT>::std_type bit_type;
TypeCategoryVisitor()
{}
Expand All @@ -774,7 +760,7 @@ integer, floating point, complex floating point and bitmask cases.
typename boost::enable_if_c<
boost::is_integral<T>::value, void
>::type
operator() (ome::compat::shared_ptr< ::ome::files::PixelBuffer<T> >& buf)
operator() (std::shared_ptr<::ome::files::PixelBuffer<T>>& buf)
{
// Integer algorithm.
}
Expand All @@ -784,7 +770,7 @@ integer, floating point, complex floating point and bitmask cases.
typename boost::enable_if_c<
boost::is_floating_point<T>::value, void
>::type
operator() (ome::compat::shared_ptr< ::ome::files::PixelBuffer<T> >& buf)
operator() (std::shared_ptr<::ome::files::PixelBuffer<T>>& buf)
{
// Floating point algorithm.
}
Expand All @@ -794,15 +780,15 @@ integer, floating point, complex floating point and bitmask cases.
typename boost::enable_if_c<
boost::is_complex<T>::value, void
>::type
operator() (ome::compat::shared_ptr< ::ome::files::PixelBuffer<T> >& buf)
operator() (std::shared_ptr<::ome::files::PixelBuffer<T>>& buf)
{
// Complex floating point algorithm.
}
// BIT/bool pixel type. Note this is a simple overload since it is
// a simple type, not a category of different types.
void
operator() (ome::compat::shared_ptr< ::ome::files::PixelBuffer<bit_type> >& buf)
operator() (std::shared_ptr<::ome::files::PixelBuffer<bit_type>>& buf)
{
// Boolean algorithm.
}
Expand Down
9 changes: 4 additions & 5 deletions docs/sphinx/examples/metadata-formatreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,16 @@
*/

#include <iostream>
#include <memory>

#include <boost/filesystem/path.hpp>

#include <ome/files/VariantPixelBuffer.h>
#include <ome/files/in/TIFFReader.h>

#include <ome/compat/memory.h>

using boost::filesystem::path;
using ome::compat::make_shared;
using ome::compat::shared_ptr;
using std::make_shared;
using std::shared_ptr;
using ome::files::dimension_size_type;
using ome::files::FormatReader;
using ome::files::MetadataMap;
Expand Down Expand Up @@ -98,7 +97,7 @@ namespace
{
// Print plane position (for this image index and plane
// index)
ome::compat::array<dimension_size_type, 3> coords =
std::array<dimension_size_type, 3> coords =
reader.getZCTCoords(p);
stream << "\tPosition of Plane " << p << ':'
<< "\n\t\tTheZ = " << coords[0]
Expand Down
Loading

0 comments on commit e5a4d5c

Please sign in to comment.