是否可以从成员函数中检测对象是否是临时对象?

Posted

技术标签:

【中文标题】是否可以从成员函数中检测对象是否是临时对象?【英文标题】:Is it possible to detect whether object is a temporary from within member function? 【发布时间】:2016-06-08 18:11:12 【问题描述】:

我正在使用指向实现的习惯用法在不可变对象上实现装饰器模式。基本上我的设置是这样的

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;
;

这里,decorateWith 函数应该有不同的行为,这取决于它被调用的对象是否是临时的。如果在非临时对象上调用它,它应该返回一个新的 Object 实例,我必须在其中制作当前 Object 的深层副本并将其存储在装饰器的 unique_ptr 中,而新 Object 本身的 impl 指针指向装饰器。 但是,如果在一个临时对象上调用 decorateWith,那么创建一个 ObjectDecorator 并将当前对象的 impl 指针移动到装饰器的 impl 指针中并让该对象指向新的装饰器就足够了。

为了强调我需要一种方法来从对 decorateWith 的调用中确定对象是否是临时对象,然后根据该检查的结果使用标记调度。这可能吗?

最好的 Xodion

编辑:示例调用者代码可能如下所示:

decorateWith 在非临时对象上调用

int main() 
    Object x;

    // this call does not modify x so it can be reused later
    Object y = x.decorateWithstd::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 被临时调用

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()
 

【问题讨论】:

你的解释最好用示例调用代码来支持。 您是要确定调用的Object decorateWith 是临时的,还是decorateWith 的参数是临时的? 我只想在调用decorateWith的对象是临时对象时有条件地移动,否则进行深拷贝,所以它是关于如何检查对象是否是临时对象。正如下面的答案所示,不需要某种类型特征,因为可以使用 ref-qualifiers 重载。 【参考方案1】:

您可以在成员函数上使用 ref 限定符。从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"

所以在你的情况下,你会想要这样的东西

 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;

【讨论】:

是的,确实,但是我需要的是 ref-qualifiers。【参考方案2】:

您可以使用引用限定符重载成员函数,类似于使用 const 重载 const 和非 const 对象的方式:

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) const&

    // implementation if this is not a temporary


Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&

    // implementation if this IS a temporary

【讨论】:

【参考方案3】:

是的。如果你实现了以下两种方法:

 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
 Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;

如果*this 是右值,则将调用第二个。

【讨论】:

以上是关于是否可以从成员函数中检测对象是否是临时对象?的主要内容,如果未能解决你的问题,请参考以下文章

在非构造的“对象”上调用非虚拟成员函数是不是定义明确? [复制]

成员对象和封闭类

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

验证函子的目标对象

是否立即为作为类成员的对象数组调用构造函数?

成员变量,成员函数和对象初始化