1

I'm developing a new version of a CLI utility which generates accessors and would like to add a decorate feature.

In order to implement that, I would like to know what is the best way to implement a decorator in C++ and eventually C++11.

For example, with such an interface:

class IHello
{
public:
    virtual void hello(std::string name) = 0;
};

I have two possibility, either I copy the parameter name again to pass it to the object, or I created an rvalue reference with std::move semantic.

I thus have two different decorator. The first passing arguments by copy:

class HelloCopy : public IHello
{
public:
    HelloCopy(IHello& instance)
        :instance (instance)
    {
    }

    virtual void hello(std::string name) override
    {
        this->instance.hello(name);
    }

private:
    IHello& instance;
};

The second passing argument by rvalue-reference:

class HelloRValue : public IHello
{
public:
    HelloRValue(IHello& instance)
        :instance (instance)
    {
    }

    virtual void hello(std::string name) override
    {
        this->instance.hello(std::move(name));
    }

private:
    IHello& instance;
};

My question is: What is the best (most efficient) way to implement a decorator?

I could also make the decorated method's argument and rvalue reference, but as I want to comply with the interface (hence the explicit override), I can't change it.

Mark B
  • 95,107
  • 10
  • 109
  • 188
Jaffa
  • 12,442
  • 4
  • 49
  • 101
  • Why not using const references down to the decorated object that *may* decide to make a copy at that stage ? – J.N. Mar 07 '12 at 23:40
  • 1
    @J.N. I won't always have the control on the interface to decorate, and it may not be a expected behavior. In case of reference there is no problem, as I simply reuse it (or std::forward in case of rvalue reference). – Jaffa Mar 07 '12 at 23:43
  • Why the `instance` reference? – Xeo Mar 08 '12 at 00:03
  • @Xeo If should keep a reference to the underlying object – Jaffa Mar 08 '12 at 00:04
  • Yeah, but why? Your `HelloXXX` *is* the underlying object already, you inherit from it. Just do `this->IHello::hello(std::move(name))`. – Xeo Mar 08 '12 at 00:10
  • @Sjoerd: Alright, nvm me then. :) – Xeo Mar 08 '12 at 00:44
  • IHello is to be seen as an interface, as it has only virtual pure members. Thus it's not the underlying object, as it is not even instanciable. The underyling object is for exemple a class Hello which implements hello method by realizing IHello interface. – Jaffa Mar 08 '12 at 06:47
  • Would [this](http://stackoverflow.com/q/7592630/726300) question and its answers help? – Luc Danton Mar 08 '12 at 19:09

1 Answers1

1

You seem to have a misconception of what moving really means:

A move is just a better copy.

As such, a move is never worse than a copy, and if the type contains external data, it is always faster (assuming a sane move constructor).

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Thus you would preferably use the rvalue-reference form? – Jaffa Mar 07 '12 at 23:58
  • @Geoffroy: I'd rather have it called `HelloMove`, but yes. – Xeo Mar 08 '12 at 00:10
  • Okay, thank you for your point of view. The name was just for the example. So using such a construct, would it copy the value only once? – Jaffa Mar 08 '12 at 06:50
  • @Xeo: do you know if in the OP's question for the `HelloCopy` case the compiler is allowed to move from `name` instead of copying ? It seems unlikely to me (supposing we output the string in the destructor, the result would change), but it does look like an inserting opportunity. – Matthieu M. Mar 08 '12 at 07:25
  • @Matthieu: According to the standard, the compiler is only allowed to insert a `std::move` when returning a local variable (aka, when copy elision *could* be performed, but isn't for whatever reason). – Xeo Mar 08 '12 at 13:22
  • 1
    A move is not just a better copy. It leaves the source in an unspecified state. – Johannes Schaub - litb Mar 11 '12 at 15:43