Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to detect whether object is a temporary from within member function?

I'm implementing a decorator pattern on immutable objects with the pointer-to-implementation idiom. Basically my setup looks like this

struct Object : ObjectBase {
     void doSmth() override {
         impl->doSmth();
     }
     // this is the function I'd like to implement
     Object decorateWith(std::unique_ptr<ObjectDecorator>&&);
private:
     std::unique_ptr<ObjectBase> impl;
};

struct ObjectDecorator : ObjectBase {
    void doSmth() override {
        // do some stuff
        impl->doSmth();
        // do some more stuff
    }
private:
    std::unique_ptr<ObjectBase> impl;
};

Here, the decorateWith function is supposed to have different behavior depending on the whether the object it is callen on is a temporary or not. If it is called on a non-temporary object, it is supposed to return a new Object instance where I have to make a deep copy of the current Object and store it in the unique_ptr of the decorator while the impl pointer of the new Object itself is pointing to the decorator. If, however, decorateWith is called on a temporary, it suffices to create a ObjectDecorator and just move the impl-pointer of the current object into the impl pointer of the decorator and let the object point to the new decorator.

In order to impelement that I need a way to determine from within the call to decorateWith whether the object is a temporary or not and then use tag-dispatch based on the result of that check. Is that possible?

Best Xodion

EDIT: Sample caller code could look like this:

  • decorateWith is called on a non-temporary

    int main() {
        Object x{};
    
        // this call does not modify x so it can be reused later
        Object y = x.decorateWith{std::make_unique<ObjectDecorator>()};
        y.doSmth();
    
        // do some other stuff here
    
        // here, if I had moved the impl-unique_ptr in the decorateWith
        // call this would now segfault since I'd call nullptr->doSmth();
        x.doSmth();
    
    }
    
  • decorateWith is called on a temporary

    int main() {
        Object x = Object{}.decorateWith(std::make_unique<ObjectDecorator>())
                           .decorateWith(std::make_unique<ObjectDecorator>())
                           .decorateWith(std::make_unique<ObjectDecorator>());
         // in this case it would be unneccessary to make a deep copy of all
         // previous instances so I'd like to only move the impl poiner every time
         x.doSmth()
     }
    
like image 731
Corristo Avatar asked Jun 08 '16 18:06

Corristo


People also ask

Is temporary object created in return by reference?

Explanation: A temporary object is created when an object is returned by value. The temporary object is used to copy the values to another object or to be used in some way. The object holds all the values of the data members of the object.

What are temporary objects C++?

A temporary object is an unnamed object created by the compiler to store a temporary value.


1 Answers

You can have ref-qualifiers on member functions. Copied example from en.cppreference.com

#include <iostream>
struct S {
    void f() & { std::cout << "lvalue\n"; }
    void f() &&{ std::cout << "rvalue\n"; }
};

int main(){
    S s;
    s.f();            // prints "lvalue"
    std::move(s).f(); // prints "rvalue"
    S().f();          // prints "rvalue"
}

So in your situation, you would want to have something like this

 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;
like image 51
kmdreko Avatar answered Sep 22 '22 06:09

kmdreko