jeudi 1 juillet 2021

Copy object only if needed

We discovered, that we use UB thing (order of temporary objects constructors) everywhere in code, so we decide to slightly rewrite one of code pieces. Suppose we have following code:

#include <iostream>
#include <string>

#include <boost/optional.hpp>

namespace trick
{

template<typename T>
struct maybe_holder
{
public:
   maybe_holder() = default;
   maybe_holder(T&& v) : value(v)
   {
   }

   boost::optional<T> value;
};

}

struct some_base_type
{
    some_base_type(void* v) : value(v) {}
    void* value;
};

template <typename T>
class some_type : private trick::maybe_holder<T>, public some_base_type
{
public:
    some_type(T& t) :
    some_base_type(&t)
    {
        std::cout << "called ref ctor" << std::endl;
    }
    
    some_type(T const& t) :
    some_base_type(&const_cast<T&>(t))
    {
        std::cout << "called cref ctor" << std::endl;
    }

    some_type(T&& t)
        : trick::maybe_holder<T>(std::forward<T>(t)), some_base_type(&trick::maybe_holder<T>::value.get())
   {
        std::cout << "called rvalue ctor" << std::endl;
   }
};

template <typename T>
some_type<T> do_smth(T & t)
{
    return (some_type<T>(t));
}

template <typename T>
some_type<T> do_smth(T const & t)
{
    return (some_type<T>(t));
}

template<typename T>
some_type<T> do_smth(T && t)
{
    return (some_type<T>(std::forward<T>(t)));
}

int main()
{
    do_smth(std::string("abc"));
    std::string s;
    do_smth(s);
    const std::string ss = "11";
    do_smth(ss);
}

live example

Now it works fine on any kind of object (temporary will be copied to optional, then pointer to value constructed before other base class would be gotten). So, basically question is, is there is any way to avoid overhead from optional and simply not depend on it? Thanks in advance.

I tried to write something like this:

template<typename T>
struct maybe_object {};
    
template<typename T>
struct maybe_object<T&&>
{
public:
    maybe_object(T&& v) : value(std::forward(v)) {}
    typename std::remove_reference<T>::type value;
};

But as far as I see we can't use this thing, cause it's just dependent on type of template.

Aucun commentaire:

Enregistrer un commentaire