patterncppMinor
Polymorphic (owned) reference wrapper for class hierarchies
Viewed 0 times
referencehierarchiespolymorphicwrapperforownedclass
Problem
Rationale: I often have the requirement to own object instances, while preserving polymorphic behavior (i.e. own the object and hold it by pointer, or reference).
This is usually expressed as a pointer (most of the times,
To avoid this, I have implemented a polymorphic wrapper for a (base) class, that holds a pointer to the base class, and allows it's population using a specialization.
The wrapper allows implicit conversion to the held type (as a
Please review the code, and let me know if there are any pitfalls or design/implementation problems with it (one known limitation is described at the end).
```
#pragma once
#include
#include
#include
#include
#include
namespace stdex {
inline namespace details {
/// @brief Deep copy construct from (Specialized&)*src
///
/// @retval nullptr if src is nullptr
/// @retval Specialized clone of *src
///
/// @note Undefined behavior if src does not point to a Specialized*
template
Base polymorphic_clone (const Base src) {
static_assert(std::is_base_of::value,
"Specialized is not a specialization of Base");
if (src == nullptr)
return nullptr;
return new Specialized{ static_cast(*src) };
}
}
/// @brief polymorphic reference interface over a base class
///
/// Respects polymorphic behavior of class ref.
/// Instances have deep copy semantics (clone) and
/// "[const] Base&" interface
///
/// @n
This is usually expressed as a pointer (most of the times,
std::unique_ptr), but when the pointer is stored in a std:: container, client syntax becomes tricky (with - for example - vector iterators being dereferenced to a pointer - instead of a reference).To avoid this, I have implemented a polymorphic wrapper for a (base) class, that holds a pointer to the base class, and allows it's population using a specialization.
The wrapper allows implicit conversion to the held type (as a
Base [const] reference) and implements fast, non-intrusive cloning, for the held type. This is based on copy construction of the Specialized type and stdex::details::polymorphic_clone template specialization, to clone the correct Specialized type).Please review the code, and let me know if there are any pitfalls or design/implementation problems with it (one known limitation is described at the end).
```
#pragma once
#include
#include
#include
#include
#include
namespace stdex {
inline namespace details {
/// @brief Deep copy construct from (Specialized&)*src
///
/// @retval nullptr if src is nullptr
/// @retval Specialized clone of *src
///
/// @note Undefined behavior if src does not point to a Specialized*
template
Base polymorphic_clone (const Base src) {
static_assert(std::is_base_of::value,
"Specialized is not a specialization of Base");
if (src == nullptr)
return nullptr;
return new Specialized{ static_cast(*src) };
}
}
/// @brief polymorphic reference interface over a base class
///
/// Respects polymorphic behavior of class ref.
/// Instances have deep copy semantics (clone) and
/// "[const] Base&" interface
///
/// @n
Solution
Sometimes you are not using universal references in the right way (i.e. use always
The assignment operator takes the
I don't see big problems in your implementation, but I recommend you to compare your approach with the Sean Parent's one (see also http://youtu.be/bIhUE5uUFOA), as already suggested by @dyp. One limitation, for example is that you are not using Small Buffer Optimization and you are forcing polymorphism trough inheritance.
There are other implementations providing value semantics along with polymorphism. For example, Adobe poly and Boost Type Erasure (see usage examples here).
std::forward when passing them around and not std::move). Fix it in the implementation of to_polymorphic, for example.The assignment operator takes the
other variable by value. Consider splitting it in a (default) move assignment operator noexcept that takes by rvalue-reference and a copy assignment operator that takes by const reference and performs a clone.I don't see big problems in your implementation, but I recommend you to compare your approach with the Sean Parent's one (see also http://youtu.be/bIhUE5uUFOA), as already suggested by @dyp. One limitation, for example is that you are not using Small Buffer Optimization and you are forcing polymorphism trough inheritance.
There are other implementations providing value semantics along with polymorphism. For example, Adobe poly and Boost Type Erasure (see usage examples here).
Context
StackExchange Code Review Q#54371, answer score: 3
Revisions (0)
No revisions yet.