C++模板成员初始化: move-construction with rvalue but reference with lvalue

标签 c++ templates deep-copy rvalue shallow-copy

我的类的构造函数初始化引用成员。我怎样才能安全地传递临时对象以初始化这些引用成员?

我有一个对象类和对这些对象执行的操作类。这些操作都派生自提供公共(public)接口(interface)的抽象基类。否则,这些操作可能包含特定实现的大量附加信息。

class Object;

class Operation {
  public:
  virtual void do_something( Object& obj ) = 0;
  /* ... */
}

class FooOperation : public Operation { /*...*/ }
class BarOperation : public Operation { /*...*/ }
class BazOperation : public Operation { /*...*/ }

我也想组合操作。一种正确的方法是使用以下类:

class ComposedOperation : Operation {

  private:

    const Operation& m_op1; const Operation& m_op2;

  public:

    ComposedOperation( const Operation& op1, const Operation& op2 )
    : m_op1(op1), m_op2( op2 ) { };

    void do_something( Object& obj ) override 
    { m_op1.do_something(obj); m_op2.do_something(obj); }
}

问题在于组合操作只能绑定(bind)左值引用。像下面这样的组合是危险的:

auto op = ComposedOperation( BarOperation(), ComposedOperation( FooOperation(), BazOperation() ) );

如何让类知道第一个/第二个操作是左值还是右值?最好不要重载构造函数。我想知道模板是否可以提供帮助。

最佳答案

我认为有两种选择:

  1. 将所有操作存储在与树分开的某个地方,并确保它们的生命周期比对它们的引用更长。

  2. 让每个 Operation 拥有自己的 child ,并按值或在 unique_ptr 中存储它们。

选项 1 在某些情况下可能有用(如果您在某处有一个操作注册表,并且 Operation 树只是一个组织的东西)。但是,从您的使用示例来看,情况似乎并非如此。

选项 2 绝对更简单,实现移动语义应该可以避免任何性能问题。

如果你真的需要在特定实例中避免复制/移动,你可以创建一个 Ref 包装器,它通过引用存储一个 Operation,并实现 Operation 界面本身。使用它时,您显然需要自己确保正确的生命周期。

所以(大约):

template<class A, class B>
struct FooOperation {
    A a; B b;

    // ... implement operation concept
};

template<class T>
struct Ref {
    T& t;

    // ... implement operation concept
};

auto a = BarOperation();
auto b = FooOperation<Ref<A>, B>(Ref(a), BazOperation());

或者如果我们需要运行时多态性:

struct FooOperation : Operation {
    std::unique_ptr<Operation> a, b;

    // ... implement operation interface
};

struct Ptr : Operation {
    Operation* t;

    // ... implement operation interface
};

auto a = std::make_unique<BarOperation>();
auto b = FooOperation(std::make_unique<Ptr>(a), std::make_unique<BazOperation>());

关于C++模板成员初始化: move-construction with rvalue but reference with lvalue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57964380/

相关文章:

c++ - 使用指针写入数组元素的问题

c++ - 是否可以使用 cmake 为没有 pod 的 Xcode 11 链接 xcframework (FirebaseCore.xcframework)?我找不到例子

c++ - 模板声明说明

python - 在 virtualenv 中全新安装后缺少 Django 管理/模板/文件夹

c++ - 使用 `void_t` 检查类是否具有具有特定签名的方法

java - 如何使用ObjectOutputStream.writeObject()+Base64 (Java)深度序列化对象?

kotlin - Kotlin 中的深度复制

c++ - 在没有 Windows.h 的情况下制作 OpenGL 应用程序

c++ - 深度复制包含引用成员的结构 (C++)

c++ - 如何检查两个数组或列表是否相同?