I am trying to create my own boost::adaptors::transformed.
Here is the related boost code.
Here is its usage (modified from a SO answer by LogicStuff):-
C funcPointer(B& b){
//"funcPointer" is function convert from "B" to "C"
return instance-of-C
}
MyArray<B> test; //<-- any type, must already have begin() & end()
for(C c : test | boost::adaptor::transformed(funcPointer)) {
//... something ....
}
The result will be the same as :-
for(auto b : test) {
C c = funcPointer(b);
//... something ...
}
My Attempt
I created CollectAdapter that aim to work like boost::adaptor::transformed.
It works OK in most common cases.
Here is the full demo and back up. (same as below code)
The problematic part is CollectAdapter - the core of my library.
I don't know whether I should cache the collection_ by-pointer or by-value.
CollectAdapter encapsulates underlying collection_ (e.g. pointer to std::vector<>) :-
template<class COLLECTION,class ADAPTER>class CollectAdapter{
using CollectAdapterT=CollectAdapter<COLLECTION,ADAPTER>;
COLLECTION* collection_; //<---- #1 problem? should cache by value?
ADAPTER adapter_; //<---- = func1 (or func2)
public: CollectAdapter(COLLECTION& collection,ADAPTER adapter){
collection_=&collection;
adapter_=adapter;
}
public: auto begin(){
return IteratorAdapter<
decltype(std::declval<COLLECTION>().begin()),
decltype(adapter_)>
(collection_->begin(),adapter_);
}
public: auto end(){ ..... }
};
IteratorAdapter (used above) encapsulates underlying iterator, change behavior of operator* :-
template<class ITERATORT,class ADAPTER>class IteratorAdapter : public ITERATORT {
ADAPTER adapter_;
public: IteratorAdapter(ITERATORT underlying,ADAPTER adapter) :
ITERATORT(underlying),
adapter_(adapter)
{ }
public: auto operator*(){
return adapter_(ITERATORT::operator*());
}
};
CollectAdapterWidget (used below) is just a helper class to construct CollectAdapter-instance.
It can be used like:-
int func1(int i){ return i+10; }
int main(){
std::vector<int> test; test.push_back(5);
for(auto b:CollectAdapterWidget::createAdapter(test,func1)){
//^ create "CollectAdapter<std::vector<int>,func1>" instance
//here, b=5+10=15
}
}
Problem
The above code works OK in most cases, except when COLLECTION is a temporary object.
More specifically, dangling pointer potentially occurs when I create adapter of adapter of adapter ....
int func1(int i){ return i+10; }
int func2(int i){ return i+100; }
template<class T> auto utilityAdapter(const T& t){
auto adapter1=CollectAdapterWidget::createAdapter(t,func1);
auto adapter12=CollectAdapterWidget::createAdapter(adapter1,func2);
//"adapter12.collection_" point to "adapter1"
return adapter12;
//end of scope, "adapter1" is deleted
//"adapter12.collection_" will be dangling pointer
}
int main(){
std::vector<int> test;
test.push_back(5);
for(auto b:utilityAdapter(test)){
std::cout<< b<<std::endl; //should 5+10+100 = 115
}
}
This will cause run time error. Here is the dangling-pointer demo.
In the real usage, if the interface is more awesome, e.g. use | operator, the bug will be even harder to be detected :-
//inside "utilityAdapter(t)"
return t|func1; //OK!
return t|func1|func2; //dangling pointer
Question
How to improve my library to fix this error while keeping performance & robustness & maintainablilty near the same level?
In other words, how to cache data or pointer of COLLECTION (that can be adapter or real data-structure) elegantly?
Alternatively, if it is easier to answer by coding from scratch (than modifying my code), go for it. :)
My workarounds
The current code caches by pointer.
The main idea of workarounds is to cache by value instead.
Workaround 1 (always "by value")
Let adapter cache the value of COLLECTION.
Here is the main change:-
COLLECTION collection_; //<------ #1
//changed from .... COLLECTION* collection_;
Disadvantage:-
Whole data-structure (e.g. std::vector) will be value-copied - waste resource.
(when use for std::vector directly)
Workaround 2 (two versions of library, best?)
I will create 2 versions of the library - AdapterValue and AdapterPointer.
I have to create related classes (Widget,AdapterIterator,etc.) as well.
AdapterValue - by value. (designed for utilityAdapter())
AdapterPointer - by pointer. (designed for std::vector)
Disadvantage:-
Duplicate code a lot = low maintainability
Users (coders) have to be very conscious about which one to pick = low robustness
Workaround 3 (detect type)
I may use template specialization that do this :-
If( COLLECTION is an "CollectAdapter" ){ by value }
Else{ by pointer }
Disadvantage:-
Not cooperate well between many adapter classes.
They have to recognize each other : recognized = should cache by value.
Sorry for very long post.
I personally would go with template specialisation – however, not specialise the original template, but a nested class instead:
template<typename Collection, typename Adapter>
class CollectAdapter
{
template<typename C>
class ObjectKeeper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C, typename A>
class ObjectKeeper <CollectAdapter<C, A>>
{
CollectAdapter<C, A> object;
public:
CollectAdapter<C, A>* operator*() { return &object; };
CollectAdapter<C, A>* operator->() { return &object; };
};
ObjectKeeper<Collection> keeper;
// now use *keeper or keeper-> wherever needed
};
The outer class then covers both cases by just always using pointers while the nested class hides the differences away.
Sure, incomplete (you yet need to add appropriate constructors, for instance, both to outer and inner class), but it should give you the idea...
You might even allow the user to select if she/he wants to copy:
template<typename Collection, typename Adapter, bool IsAlwaysCopy = false>
class CollectAdapter
{
template<typename C, bool IsCopy>
class ObjectWrapper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C>
class ObjectWrapper<C, true>
{
C object;
public:
C* operator*() { return &object; };
C* operator->() { return &object; };
};
// avoiding code duplication...
template<typename C, bool IsCopy>
class ObjectKeeper : public ObjectWrapper<C, IsCopy>
{ };
template<typename C, typename A, bool IsCopy>
class ObjectKeeper <CollectAdapter<C, A>, IsCopy>
: public ObjectWrapper<CollectAdapter<C, A>, true>
{ };
ObjectKeeper<Collection> keeper;
};
In my indexed_view I store the value of the collection if it is an rvalue, and store a reference if it is an lvalue. You could do the same here: overload your operator| for both rvalues and lvalues.
template<typename Collection,typename Filter>
auto operator|(Collection&& collection,Filter filter){
return create_adapter_for_rvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection const& collection,Filter filter){
return create_adapter_for_const_lvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection & collection,Filter filter){
return create_adapter_for_non_const_lvalue_collection(collection,filter);
}
Related
If I have the following:
class Animal {};
class Penguin : public Animal {};
class Snake : public Animal {};
class Zoo
{
std::vector<std::shared_ptr<Animal>> animals;
public:
const std::vector<std::shared_ptr<Animal>>& GetAnimals() { return animals; }
std::shared_ptr<Penguin> AddPenguin()
{
auto result = std::make_shared<Penguin>();
animals.push_back(result);
return result;
}
std::shared_ptr<Snake> AddSnake()
{
auto result = std::make_shared<Snake>();
animals.push_back(result);
return result;
}
};
I'd like to keep const correctness, and be able to add the following method:
const std::vector<std::shared_ptr<const Animal>>& GetAnimals() const
{
return animals;
}
However, that doesn't compile because the return type doesn't match animals. As the const is embedded deep in the type, const_cast isn't able to convert.
However, this compiles and appears to behave:
const std::vector<std::shared_ptr<const Animal>>& GetAnimals() const
{
return reinterpret_cast<const std::vector<std::shared_ptr<const Animal>>&>(animals);
}
I realize reinterpret_casts can be dangerous, but are there any dangers to use it in this scenario? Do the types being cast between have the same memory layout? Is the only effect of this to prevent the caller from then calling any non-const methods of Animal?
Update
I've realized this isn't entirely const correct. The caller could call .reset() on one of the elements of the vector, which would still modify the zoo. Even so, I'm still intrigued what the answer is.
Update on the update
I got that wrong, the code I was trying accidentally copied the shared_ptr and so the shared_ptr in the vector can't be reset when the vector is const.
std::shared_ptr<Animal> and std::shared_ptr<const Animal> are fundamentally different types. Messing with reinterpret_cast can lead to very strange bugs down the road (mostly due to optimizations, I would imagine). You have two options: create a new std::shared_ptr<const Animal> for each std::shared_ptr<Animal>, or return a complex proxy type (something like a view of the vector).
That said, I question the need for GetAnimals. If Zoo is meant to be a collection of pointers to animals, can't you provide access functions like size, operator[], and perhaps iterators? This does involve more effort, but if all you want is a function that returns the whole vector, why have a Zoo class in the first place? If Zoo contains other data and manages more than just a vector of animals, then I would make a separate class to take care of that part, AnimalList or something. That class can then provide appropriate access functions.
Something else you might try is to keep a std::shared_ptr<std::vector<Animal>> instead that you can easily convert into a std::shared_ptr<const std::vector<Animal>>. That may or may not be relevant depending on the reason you need shared pointers.
You can probably solve your problem with std::experimental::propagate_const. It is a wrapper for pointer-like types that properly propagates const-correctness.
A const std::shared_ptr<Animal> holds a mutable Animal. Retrieving a mutable reference to the mutable animal is legal, because the pointer itself is not changed. Vice versa, a std::shared_ptr<Animal const> will always hold a const Animal. You would have to explicitly cast away constness to mutate the held element which is ugly to say the least. Dereferencing a std::experimental::propagate_const<std::shared_ptr<Animal>> on the other hand returns a Animal const& if it is const, and a Animal& if it is not const.
If you wrap your shared pointers in std::experimental::propagate_const you can equip Zoo with a const and a non-const getter for your animals vector and have const-correctness (or you could make animals a public data member, since the getters don't do anything special. This would make your API more transparent):
#include <vector>
#include <memory>
#include <experimental/propagate_const>
#include <type_traits>
class Animal {};
class Penguin : public Animal {};
class Snake : public Animal {};
class Zoo
{
template <typename T>
using pointer_t = std::experimental::propagate_const<std::shared_ptr<T>>;
std::vector<pointer_t<Animal>> animals;
public:
// const-getter
auto const& GetAnimals() const
{
return animals;
}
// non-const getter
auto& GetAnimals()
{
return animals;
}
std::shared_ptr<Penguin> AddPenguin()
{
auto result = std::make_shared<Penguin>();
animals.push_back(result);
return result;
}
std::shared_ptr<Snake> AddSnake()
{
auto result = std::make_shared<Snake>();
animals.push_back(result);
return result;
}
};
int main() {
Zoo zoo;
zoo.AddSnake();
// non-const getter will propagate mutability through the pointer
{
auto& test = zoo.GetAnimals()[0];
static_assert(std::is_same<Animal&, decltype(*test)>::value);
}
// const-getter will propagate const through the pointer
{
Zoo const& zc = zoo;
auto& test = zc.GetAnimals()[0];
static_assert(std::is_same<Animal const&, decltype(*test)>::value);
}
return 0;
}
https://godbolt.org/z/1rd8YraMc
The only downsides I can think of are the discouraging "experimental" namespace and the fact that afaik MSVC hasn't implemented it yet, so it is not as portable as it could be....
If that bothers you, you can write your own propagate_const wrapper type, as #Useless suggested:
template <typename Ptr>
class propagate_const
{
public:
using value_type = typename std::remove_reference<decltype(*Ptr{})>::type;
template <
typename T,
typename = std::enable_if_t<std::is_convertible<T, Ptr>::value>
>
constexpr propagate_const(T&& p) : ptr{std::forward<T>(p)} {}
constexpr value_type& operator*() { return *ptr; }
constexpr value_type const& operator*() const { return *ptr; }
constexpr value_type& operator->() { return *ptr; }
constexpr value_type const& operator->() const { return *ptr; }
private:
Ptr ptr;
};
https://godbolt.org/z/eGPPPxef4
Before anything: I'm not a developer and I might not understand some of your messages, and as English is not my native language my question could be hard to understand.
Considering :
class MyVector
{
std::vector<command> vec;
std::mutex vector_m;
public:
void MVpush_back(command t)
{
this->vector_m.lock();
this->vec.push_back(t);
this->vector_m.unlock();
}
};
command is a custom class (its content doesn't seem relevant here; copy constructor does exist).
Basically, as I have a lot of possible writer & readers, thus I want to force the use of the mutex to access to the vec parameter.
As I'll only use push_back(), erase() and find() I could redefine them, but I was wondering if there is a way not have to redefine all functions.
something like:
<template> safe(*function name*<template>)
{
this->vector_m.lock();
<template> retval = vec.*function name*<parameter>;
this->vector_m.unlock();
return retval;
}
where the function to call is a kind of parameter...
I thought it could be done using std::initializer_list<type> but the type requirement is blocking.
Is there a way to do such a thing?
Rephrased question: is there a way to push a function with parameter(1) as parameter of a function(2) and make function(2) call function(1) ?
If you don't mind sacrificing the use of the member access operator (.), you can wrap all the vector operations neatly into lockable operations.
class MyVector {
std::vector<command> vec;
std::mutex vector_m;
struct locker {
MyVector& _ref;
locker(MyVector& parent) : _ref(parent) {
_ref.vector_m.lock();
}
~locker() { _ref.vector_m.unlock(); }
std::vector<command>* operator->() && { return &_ref.vec; }
};
public:
locker operator->() { return {*this}; }
};
Now, every access to the underlying vector will lock and unlock the vector for the duration of the operation:
MyVector mv;
mv->push_back(/* ... */);
// This locks the mutex before doing the push back
// And unlocks it immediately after, even in the face of exceptions.
The magic is in operator-> acting in a transitive manner. It is applied to the return value of itself until a regular pointer is returned, which is then accessed as usual. But every temporary along the way is created and destroyed in LIFO order. So the temporary MyVector::locker object has a lifetime that is just the duration of the access more or less.
Here's a quick not particularly fantastic version of the suggestion I made in the comments; not compiled or tested; just something so that you can get the idea.
template<class T>
class OverkillProtector {
private:
T& d;
std::unique_lock<std::mutex>lock ;
public:
OverkillProtector(T& d_, std::mutex& m_) :
d(d_),
lock(m_)
{}
OverkillProtector(const OverkillProtector&) = delete;
OverkillProtector& operator =(const OverkillProtector&) = delete;
T& getValue() { return d; }
const T& getValue() const { return d; }
};
Note that in the (default) desturctor, the unique lock will be destroyed, which will release the mutex. Note that the lifetime of this object is required to be less than that of the mutex or the data you're wrapping.
You might do something like:
class MyVector
{
std::vector<command> vec;
std::mutex vector_m;
public:
template <typename F>
decltype(auto) Do(F&& f)
{
std::unique_lock<std::mutex> lock{vector_m};
return std::forward<F>(f)(vec);
}
};
With usage similar to:
MyVector myVector;
command myCommand;
myVector.Do([&](auto& vec) { vec.push_back(myCommand); });
A template approach might look like this:
class MyVector
{
std::vector<command> vec;
mutable std::mutex vector_m;
public:
template <typename R, typename ... T, typename ... P>
R safeCall(R (std::vector<command>::*f)(T ...), P&& ... p)
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(std::forward<P>(p)...);
}
template <typename R, typename ... T, typename ... P>
R safeCall(R (std::vector<command>::*f)(T ...) const, P&& ... p) const
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(std::forward<P>(p)...);
}
};
void test()
{
MyVector v;
v.safeCall(&std::vector<int>::push_back, 7);
MyVector const* vv = &v;
int n = vv->safeCall(&std::vector<int>::operator[], 0);
}
Well, you safe the work of re-implementing the interface, but usage gets rather ugly – typedef for the vector type gets it minimally shorter, but still... A macro?
#define safe_call(V, R, F, ...) V R safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v, ., push_back, 7);
safe_call(vv, ->, operator[], 1);
Or a little shorter:
#define safe_call(V, F, ...) V safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v., push_back, 7);
safe_call(vv->, operator[], 1);
Well, I won't comment further, decide yourself...
In the end, you might bite the bullet and really duplicate the interface for the sake of more convenient usage afterwards - a helper template might facilitate the task, though:
class MyVector
{
std::vector<command> vec;
mutable std::mutex vector_m;
template <typename R, typename ... T>
R safeCall(R (std::vector<command>::*f)(T...), T... t)
{
std::lock_guard<std::mutex> l(vector_m);
return (vec.*f)(t...);
}
// const variant, too
public:
// ...
};
void MyVector::push_back(Command t)
{
safeCall(&std::vector<Command>::push_back, t);
}
Consider polymorphic classes with a base object, a derived interface, and a final object:
// base object
struct object
{
virtual ~object() = default;
};
// interfaces derived from base object
struct interface1 : object
{
virtual void print_hello() const = 0;
template<typename T>
static void on_destruction(object* /*ptr*/)
{
std::cout << "interface1::on_destruction" << std::endl;
}
};
// final object
struct derived1 : interface1
{
virtual void print_hello() const override
{
std::cout << "hello" << std::endl;
}
static std::string get_type_name()
{
return "derived1";
}
};
In the real use case, final objects are defined through a plugin system, but that is not the point. Note that I want to be able to call on_destruction when an object is destroyed (see register_object below). I want to use these classes as follows:
int main()
{
// register derived1 as an instantiable object,
// may be called in a plugin
register_object<derived1>();
// create an instance using the factory system
auto instance = create_unique<interface1>("derived1");
instance->print_hello();
return 0;
}
Using std::unique_ptr to manage the objects, I ended up with the following code for register_object:
template<typename T>
using unique = std::unique_ptr<
T,
std::function<void(object*)> // object deleter
>;
namespace
{
std::map< std::string, std::function<unique<object>(void)> > factory_map;
}
template<typename T>
void register_object()
{
factory_map.emplace(
T::get_type_name(),
[]()
{
unique<T> instance{
new T,
[](object* ptr)
{
T::on_destruction<T>(ptr);
delete ptr;
}
};
return static_move_cast<object>(
std::move(instance)
);
}
);
}
And the create* functions:
unique<object> create_unique_object(const std::string& type_name)
{
auto f = factory_map.at(type_name);
return f();
}
template<typename T>
unique<T> create_unique(const std::string& type_name)
{
return static_move_cast<T>(
create_unique_object(type_name)
);
}
You noticed in register_object and create_unique the call to static_move_cast, which is declared as:
template<typename U, typename T, typename D>
std::unique_ptr<U, D>
static_move_cast
(
std::unique_ptr<T, D>&& to_move_cast
)
{
auto deleter = to_move_cast.get_deleter();
return std::unique_ptr<U, D>{
static_cast<U*>(
to_move_cast.release()
),
deleter
};
}
The goal behind static_move_cast is to allow static_cast on std::unique_ptr while moving the deleter during the cast. The code is working, but I feel like hacking std::unique_ptr. Is there a way to refactor the code to avoid my static_move_cast?
static_move_cast is unnecessary within register_object, since you can just use the converting constructor of unique_ptr template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ):
unique<T> instance{
new T,
// ...
};
return instance;
Or, even simpler, construct and return a unique<object> directly, since T* is convertible to object*:
return unique<object>{
new T,
// ...
};
However for create_unique the use of static_move_cast is unavoidable, since the converting constructor of unique_ptr won't work for downcasts.
Note that shared_ptr has static_pointer_cast, which performs downcasts, but there is no corresponding facility for unique_ptr, presumably because it it is considered straightforward and correct to perform the cast yourself.
I would say it is good solution given the requirements. You transfer the responsibility to the caller of create_unique. He must give correct combination of type and string and string that is in the registry.
auto instance = create_unique<interface1>("derived1");
// ^^^^^^^^^^ ^^^^^^^^
// what if those two don't match?
You could improve it a bit by changing the static_cast to dynamic_cast. And the caller of create_unique should always check that he got non-null pointer before calling anything on it.
Or at least use dynamic_cast with assert in debug mode, so you catch mismatches while developing.
Alternative refactoring: Have separate factory for every existing interface.
For example I have some function pet_maker() that creates and returns a Cat or a Dog as a base Pet. I want to call this function many many times, and do something with the Pet returned.
Traditionally I would new the Cat or Dog in pet_maker() and return a pointer to it, however the new call is much slower than doing everything on the stack.
Is there a neat way anyone can think of to return as an abstraction without having to do the new every time the function is called, or is there some other way that I can quickly create and return abstractions?
Using new is pretty much inevitable if you want polymorphism. But the reason new works slowly is because it looks for free memory every time. What you could do is write your own operator new, which could, in theory, for example use pre-allocated memory chunks and be very fast.
This article covers many aspects of what you might need.
Each allocation is an overhead so you may get benefits by allocating whole arrays of objects rather than one object at a time.
You could use std::deque to achieve this:
class Pet { public: virtual ~Pet() {} virtual std::string talk() const = 0; };
class Cat: public Pet { std::string talk() const override { return "meow"; }};
class Dog: public Pet { std::string talk() const override { return "woof"; }};
class Pig: public Pet { std::string talk() const override { return "oink"; }};
class PetMaker
{
// std::deque never re-allocates when adding
// elements which is important when distributing
// pointers to the elements
std::deque<Cat> cats;
std::deque<Dog> dogs;
std::deque<Pig> pigs;
public:
Pet* make()
{
switch(std::rand() % 3)
{
case 0:
cats.emplace_back();
return &cats.back();
case 1:
dogs.emplace_back();
return &dogs.back();
}
pigs.emplace_back();
return &pigs.back();
}
};
int main()
{
std::srand(std::time(0));
PetMaker maker;
std::vector<Pet*> pets;
for(auto i = 0; i < 100; ++i)
pets.push_back(maker.make());
for(auto pet: pets)
std::cout << pet->talk() << '\n';
}
The reason to use a std::deque is that it never reallocates its elements when you add new ones so the pointers that you distribute always remain valid until the PetMaker itself is deleted.
An added benefit to this over allocating objects individually is that they don't need to be deleted or placed in a smart pointer, the std::deque manages their lifetime.
Is there a neat way anyone can think of to return as an abstraction without having to do the new every time the function is called, or is there some other way that I can quickly create and return abstractions?
TL;DR: The function need not allocate if there is already sufficient memory to work with.
A simple way would be to create a smart pointer that is slightly different from its siblings: it would contain a buffer in which it would store the object. We can even make it non-nullable!
Long version:
I'll present the rough draft in reverse order, from the motivation to the tricky details:
class Pet {
public:
virtual ~Pet() {}
virtual void say() = 0;
};
class Cat: public Pet {
public:
virtual void say() override { std::cout << "Miaou\n"; }
};
class Dog: public Pet {
public:
virtual void say() override { std::cout << "Woof\n"; }
};
template <>
struct polymorphic_value_memory<Pet> {
static size_t const capacity = sizeof(Dog);
static size_t const alignment = alignof(Dog);
};
typedef polymorphic_value<Pet> any_pet;
any_pet pet_factory(std::string const& name) {
if (name == "Cat") { return any_pet::build<Cat>(); }
if (name == "Dog") { return any_pet::build<Dog>(); }
throw std::runtime_error("Unknown pet name");
}
int main() {
any_pet pet = pet_factory("Cat");
pet->say();
pet = pet_factory("Dog");
pet->say();
pet = pet_factory("Cat");
pet->say();
}
The expected output:
Miaou
Woof
Miaou
which you can find here.
Note that it is required to specify the maximum size and alignment of the derived values that can be supported. No way around that.
Of course, we statically check whether the caller would attempt to build a value with an inappropriate type to avoid any unpleasantness.
The main disadvantage, of course, is that it must be at least as big (and aligned) as its largest variant, and all this must be predicted ahead of time. This is thus not a silver bullet, but performance-wise the absence of memory-allocation can rock.
How does it work? Using this high-level class (and the helper):
// To be specialized for each base class:
// - provide capacity member (size_t)
// - provide alignment member (size_t)
template <typename> struct polymorphic_value_memory;
template <typename T,
typename CA = CopyAssignableTag,
typename CC = CopyConstructibleTag,
typename MA = MoveAssignableTag,
typename MC = MoveConstructibleTag>
class polymorphic_value {
static size_t const capacity = polymorphic_value_memory<T>::capacity;
static size_t const alignment = polymorphic_value_memory<T>::alignment;
static bool const move_constructible = std::is_same<MC, MoveConstructibleTag>::value;
static bool const move_assignable = std::is_same<MA, MoveAssignableTag>::value;
static bool const copy_constructible = std::is_same<CC, CopyConstructibleTag>::value;
static bool const copy_assignable = std::is_same<CA, CopyAssignableTag>::value;
typedef typename std::aligned_storage<capacity, alignment>::type storage_type;
public:
template <typename U, typename... Args>
static polymorphic_value build(Args&&... args) {
static_assert(
sizeof(U) <= capacity,
"Cannot host such a large type."
);
static_assert(
alignof(U) <= alignment,
"Cannot host such a largely aligned type."
);
polymorphic_value result{NoneTag{}};
result.m_vtable = &build_vtable<T, U, MC, CC, MA, CA>();
new (result.get_ptr()) U(std::forward<Args>(args)...);
return result;
}
polymorphic_value(polymorphic_value&& other): m_vtable(other.m_vtable), m_storage() {
static_assert(
move_constructible,
"Cannot move construct this value."
);
(*m_vtable->move_construct)(&other.m_storage, &m_storage);
m_vtable = other.m_vtable;
}
polymorphic_value& operator=(polymorphic_value&& other) {
static_assert(
move_assignable || move_constructible,
"Cannot move assign this value."
);
if (move_assignable && m_vtable == other.m_vtable)
{
(*m_vtable->move_assign)(&other.m_storage, &m_storage);
}
else
{
(*m_vtable->destroy)(&m_storage);
m_vtable = other.m_vtable;
(*m_vtable->move_construct)(&other.m_storage, &m_storage);
}
return *this;
}
polymorphic_value(polymorphic_value const& other): m_vtable(other.m_vtable), m_storage() {
static_assert(
copy_constructible,
"Cannot copy construct this value."
);
(*m_vtable->copy_construct)(&other.m_storage, &m_storage);
}
polymorphic_value& operator=(polymorphic_value const& other) {
static_assert(
copy_assignable || (copy_constructible && move_constructible),
"Cannot copy assign this value."
);
if (copy_assignable && m_vtable == other.m_vtable)
{
(*m_vtable->copy_assign)(&other.m_storage, &m_storage);
return *this;
}
// Exception safety
storage_type tmp;
(*other.m_vtable->copy_construct)(&other.m_storage, &tmp);
if (move_assignable && m_vtable == other.m_vtable)
{
(*m_vtable->move_assign)(&tmp, &m_storage);
}
else
{
(*m_vtable->destroy)(&m_storage);
m_vtable = other.m_vtable;
(*m_vtable->move_construct)(&tmp, &m_storage);
}
return *this;
}
~polymorphic_value() { (*m_vtable->destroy)(&m_storage); }
T& get() { return *this->get_ptr(); }
T const& get() const { return *this->get_ptr(); }
T* operator->() { return this->get_ptr(); }
T const* operator->() const { return this->get_ptr(); }
T& operator*() { return this->get(); }
T const& operator*() const { return this->get(); }
private:
polymorphic_value(NoneTag): m_vtable(0), m_storage() {}
T* get_ptr() { return reinterpret_cast<T*>(&m_storage); }
T const* get_ptr() const { return reinterpret_cast<T const*>(&m_storage); }
polymorphic_value_vtable const* m_vtable;
storage_type m_storage;
}; // class polymorphic_value
Essentially, this is just like any STL container. The bulk of the complexity is in redefining the construction, move, copy and destruction. It's otherwise quite simple.
There are two points of note:
I use a tag-based approach to handling capabilities:
for example, a copy constructor is only available if the CopyConstructibleTag is passed
if the CopyConstructibleTag is passed, all types passed to build must be copy constructible
Some operations are provided even if the objects do not have the capability, as long as some alternative way of providing them exist
Obviously, all methods preserve the invariant that the polymorphic_value is never empty.
There is also a tricky detail related to assignments: assignment is only well-defined if both objects are of the same dynamic type, which we check with the m_vtable == other.m_vtable checks.
For completeness, the missing pieces used to power up this class:
//
// VTable, with nullable methods for run-time detection of capabilities
//
struct NoneTag {};
struct MoveConstructibleTag {};
struct CopyConstructibleTag {};
struct MoveAssignableTag {};
struct CopyAssignableTag {};
struct polymorphic_value_vtable {
typedef void (*move_construct_type)(void* src, void* dst);
typedef void (*copy_construct_type)(void const* src, void* dst);
typedef void (*move_assign_type)(void* src, void* dst);
typedef void (*copy_assign_type)(void const* src, void* dst);
typedef void (*destroy_type)(void* dst);
move_construct_type move_construct;
copy_construct_type copy_construct;
move_assign_type move_assign;
copy_assign_type copy_assign;
destroy_type destroy;
};
template <typename Base, typename Derived>
void core_move_construct_function(void* src, void* dst) {
Derived* derived = reinterpret_cast<Derived*>(src);
new (reinterpret_cast<Base*>(dst)) Derived(std::move(*derived));
} // core_move_construct_function
template <typename Base, typename Derived>
void core_copy_construct_function(void const* src, void* dst) {
Derived const* derived = reinterpret_cast<Derived const*>(src);
new (reinterpret_cast<Base*>(dst)) Derived(*derived);
} // core_copy_construct_function
template <typename Derived>
void core_move_assign_function(void* src, void* dst) {
Derived* source = reinterpret_cast<Derived*>(src);
Derived* destination = reinterpret_cast<Derived*>(dst);
*destination = std::move(*source);
} // core_move_assign_function
template <typename Derived>
void core_copy_assign_function(void const* src, void* dst) {
Derived const* source = reinterpret_cast<Derived const*>(src);
Derived* destination = reinterpret_cast<Derived*>(dst);
*destination = *source;
} // core_copy_assign_function
template <typename Derived>
void core_destroy_function(void* dst) {
Derived* d = reinterpret_cast<Derived*>(dst);
d->~Derived();
} // core_destroy_function
template <typename Tag, typename Base, typename Derived>
typename std::enable_if<
std::is_same<Tag, MoveConstructibleTag>::value,
polymorphic_value_vtable::move_construct_type
>::type
build_move_construct_function()
{
return &core_move_construct_function<Base, Derived>;
} // build_move_construct_function
template <typename Tag, typename Base, typename Derived>
typename std::enable_if<
std::is_same<Tag, CopyConstructibleTag>::value,
polymorphic_value_vtable::copy_construct_type
>::type
build_copy_construct_function()
{
return &core_copy_construct_function<Base, Derived>;
} // build_copy_construct_function
template <typename Tag, typename Derived>
typename std::enable_if<
std::is_same<Tag, MoveAssignableTag>::value,
polymorphic_value_vtable::move_assign_type
>::type
build_move_assign_function()
{
return &core_move_assign_function<Derived>;
} // build_move_assign_function
template <typename Tag, typename Derived>
typename std::enable_if<
std::is_same<Tag, CopyAssignableTag>::value,
polymorphic_value_vtable::copy_construct_type
>::type
build_copy_assign_function()
{
return &core_copy_assign_function<Derived>;
} // build_copy_assign_function
template <typename Base, typename Derived,
typename MC, typename CC,
typename MA, typename CA>
polymorphic_value_vtable const& build_vtable() {
static polymorphic_value_vtable const V = {
build_move_construct_function<MC, Base, Derived>(),
build_copy_construct_function<CC, Base, Derived>(),
build_move_assign_function<MA, Derived>(),
build_copy_assign_function<CA, Derived>(),
&core_destroy_function<Derived>
};
return V;
} // build_vtable
The one trick I use here is to let the user configure whether the types he will use in this container can be move constructed, move assigned, ... via capability tags. A number of operations are keyed on these tags and will either be disabled or less efficient if the requested capability
You can create a stack allocator instance (with some max limit of course) and pass that as an argument to your pet_maker function. Then instead of regular new do a placement new on the address provided by the stack allocator.
You can probably also default to new on exceeding max_size of the stack allocator.
One way is to work out, in advance through analysis, how many of each type of object is needed by your program.
Then you can allocate arrays of an appropriate size in advance, as long as you have book-keeping to track the allocation.
For example;
#include <array>
// Ncats, Ndogs, etc are predefined constants specifying the number of cats and dogs
std::array<Cat, Ncats> cats;
std::array<Dog, Ndogs> dogs;
// bookkeeping - track the returned number of cats and dogs
std::size_t Rcats = 0, Rdogs = 0;
Pet *pet_maker()
{
// determine what needs to be returned
if (return_cat)
{
assert(Rcats < Ncats);
return &cats[Rcats++];
}
else if (return_dog)
{
assert(Rdogs < Ndogs);
return &dogs[Rdogs++];
}
else
{
// handle other case somehow
}
}
Of course, the big trade-off in is the requirement to explicitly determine the number of each type of animal in advance - and separately track each type.
However, if you wish to avoid dynamic memory allocation (operator new) then this way - as draconian as it might seem - provides an absolute guarantee. Using operator new explicitly allows the number of objects needed to be determined at run time. Conversely, to avoid using operator new but allow some function to safely access a number of objects it is necessary to predetermine the number of objects.
It depends on the exact use case you have, and what restrictions you are willing to tolerate. For example, if you are OK with re-using the same objects rather than having new copies every time, you could return references to static objects inside the function:
Pet& pet_maker()
{
static Dog dog;
static Cat cat;
//...
if(shouldReturnDog) {
//manipulate dog as necessary
//...
return dog;
}
else
{
//manipulate cat as necessary
//...
return cat;
}
}
This works if the client code accepts that it doesn't own the object returned and that the same physical instances are reused.
There are other tricks possible if this particular set of assumptions is unsuitable.
At some point somebody is going to have to allocate the memory and initialize the objects. If doing them on demand, using the heap via new is taking too long, then why no pre-allocate a number of then in a pool. Then you can initialize each individual object on an as needed basis. The downside is that you might have a bunch of extra objects laying around for a while.
If actually initializing the object is the problem, and not memory allocation, then you can consider keeping a pre-built object around and using the Pototype pattern for quicker initialization.
For best results, memory allocation is problem and initialization time, you can combine both strategies.
You may want to consider using a (Boost) variant. It will require an extra step by the caller, but it might suit your needs:
#include <boost/variant/variant.hpp>
#include <boost/variant/get.hpp>
#include <iostream>
using boost::variant;
using std::cout;
struct Pet {
virtual void print_type() const = 0;
};
struct Cat : Pet {
virtual void print_type() const { cout << "Cat\n"; }
};
struct Dog : Pet {
virtual void print_type() const { cout << "Dog\n"; }
};
using PetVariant = variant<Cat,Dog>;
enum class PetType { cat, dog };
PetVariant make_pet(PetType type)
{
switch (type) {
case PetType::cat: return Cat();
case PetType::dog: return Dog();
}
return {};
}
Pet& get_pet(PetVariant& pet_variant)
{
return apply_visitor([](Pet& pet) -> Pet& { return pet; },pet_variant);
}
int main()
{
PetVariant pet_variant_1 = make_pet(PetType::cat);
PetVariant pet_variant_2 = make_pet(PetType::dog);
Pet& pet1 = get_pet(pet_variant_1);
Pet& pet2 = get_pet(pet_variant_2);
pet1.print_type();
pet2.print_type();
}
Output:
Cat
Dog
For example I have some function pet_maker() that creates and returns a Cat or a Dog as a base Pet. I want to call this function many many times, and do something with the Pet returned.
If you are going to discard the pet immediately after you have done something with it, you can use the technique shown in the following example:
#include<iostream>
#include<utility>
struct Pet {
virtual ~Pet() = default;
virtual void foo() const = 0;
};
struct Cat: Pet {
void foo() const override {
std::cout << "cat" << std::endl;
}
};
struct Dog: Pet {
void foo() const override {
std::cout << "dog" << std::endl;
}
};
template<typename T, typename F>
void factory(F &&f) {
std::forward<F>(f)(T{});
}
int main() {
auto lambda = [](const Pet &pet) { pet.foo(); };
factory<Cat>(lambda);
factory<Dog>(lambda);
}
No allocation required at all. The basic idea is to revert the logic: the factory no longer returns an object. Instead it calls a function providing the right instance as a reference.
The problem with this approach arises if you want to copy and store the object somewhere.
For it is not clear from the question, it's worth to propose also this solution.
My problem is pretty simple, i want to use lambda's in the same way i may use a functor as a 'comparator', let me explain a little better. I have two big structs, both of them have their own implementation of operator<, and i have also a useless class (this is just the name of the class in the context of this question) which use the two struct, everything looks like this:
struct be_less
{
//A lot of stuff
int val;
be_less(int p_v):val(p_v){}
bool operator<(const be_less& p_other) const
{
return val < p_other.val;
}
};
struct be_more
{
//A lot of stuff
int val;
be_more(int p_v):val(p_v){}
bool operator<(const be_more& p_other) const
{
return val > p_other.val;
}
};
class useless
{
priority_queue<be_less> less_q;
priority_queue<be_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
I whould like to remove the duplication in the two struct's, the simpliest idea is to make the struct a template and provide two functor to do the comparison job:
template<typename Comp>
struct be_all
{
//Lot of stuff, better do not duplicate
int val;
be_all(int p_v):val{p_v}{}
bool operator<(const be_all<Comp>& p_other) const
{
return Comp()(val,p_other.val);
}
};
class comp_less
{
public:
bool operator()(int p_first,
int p_second)
{
return p_first < p_second;
}
};
class comp_more
{
public:
bool operator()(int p_first,
int p_second)
{
return p_first > p_second;
}
};
typedef be_all<comp_less> all_less;
typedef be_all<comp_more> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
This work pretty well, now for sure i dont have any duplication in the struct code at the price of two additional function object. Please note that i'm very simplifying the implementation of operator<, the hipotetic real code does much more than just comparing two ints.
Then i was thinking about how to do the same thing using lambda (Just as an experiment).The only working solution i was able to implement is:
template<typename Comp>
struct be_all
{
int val;
function<bool(int,int)> Comparator;
be_all(Comp p_comp,int p_v):
Comparator(move(p_comp)),
val{p_v}
{}
bool operator<(const be_all& p_other) const
{
return Comparator(val, p_other.val);
}
};
auto be_less = [](int p_first,
int p_second)
{
return p_first < p_second;
};
auto be_more = [](int p_first,
int p_second)
{
return p_first > p_second;
};
typedef be_all<decltype(be_less)> all_less;
typedef be_all<decltype(be_more)> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(be_less,elem);
more_q.emplace(be_more,elem);
}
}
};
This implementation not only add a new member to the data containing struct, but have also a very poor performance, i prepared a small test in which i create one instance for all the useless class i've show you here, every time i feed the constructor with a vector full of 2 milion integers, the results are the following:
Takes 48ms to execute the constructor of the first useless class
Takes 228ms to create the second useless class (functor)
Takes 557ms to create the third useless class (lambdas)
Clearly the price i pay for the removed duplication is very high, and in the original code the duplication is still there. Please note how bad is the performance of the third implementation, ten times slower that the original one, i believed that the reason of the third implementation being slower than the second was because of the additional parameter in the constructor of be_all... but:
Actually there's also a fourth case, where i still used the lambda but i get rid of the Comparator member and of the additional parameter in be_all, the code is the following:
template<typename Comp>
struct be_all
{
int val;
be_all(int p_v):val{p_v}
{}
bool operator<(const be_all& p_other) const
{
return Comp(val, p_other.val);
}
};
bool be_less = [](int p_first,
int p_second)
{
return p_first < p_second;
};
bool be_more = [](int p_first,
int p_second)
{
return p_first > p_second;
};
typedef be_all<decltype(be_less)> all_less;
typedef be_all<decltype(be_more)> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
If i remove auto from the lambda and use bool instead the code build even if i use Comp(val, p_other.val) in operator<.
What's very strange to me is that this fourth implementation (lambda without the Comparator member) is even slower than the other, at the end the average performance i was able to register are the following:
48ms
228ms
557ms
698ms
Why the functor are so much faster than lambdas in this scenario? I was expecting lambda's to be at least performing good as the ordinary functor, can someone of you comment please? And is there any technial reason why the fourth implementation is slower than the third?
PS:
The compilator i'm using is g++4.8.2 with -O3. In my test i create for each useless class an instance and using chrono i take account of the required time:
namespace benchmark
{
template<typename T>
long run()
{
auto start=chrono::high_resolution_clock::now();
T t(data::plenty_of_data);
auto stop=chrono::high_resolution_clock::now();
return chrono::duration_cast<chrono::milliseconds>(stop-start).count();
}
}
and:
cout<<"Bad code: "<<benchmark::run<bad_code::useless>()<<"ms\n";
cout<<"Bad code2: "<<benchmark::run<bad_code2::useless>()<<"ms\n";
cout<<"Bad code3: "<<benchmark::run<bad_code3::useless>()<<"ms\n";
cout<<"Bad code4: "<<benchmark::run<bad_code4::useless>()<<"ms\n";
The set of input integers is the same for all, plenty_of_data is a vector full of 2 million intergers.
Thanks for your time
You are not comparing the runtime of a lambda and a functor. Instead, the numbers indicate the difference in using a functor and an std::function. And std::function<R(Args...)>, for example, can store any Callable satisfying the signature R(Args...). It does this through type-erasure. So, the difference you see comes from the overhead of a virtual call in std::function::operator().
For example, the libc++ implementation(3.5) has a base class template<class _Fp, class _Alloc, class _Rp, class ..._ArgTypes> __base with a virtual operator(). std::function stores a __base<...>*. Whenever you create an std::function with a callable F, an object of type template<class F, class _Alloc, class R, class ...Args> class __func is created, which inherits from __base<...> and overrides the virtual operator().