【问题标题】:How to copy an object if (and only if) it has a copy constructor?当(且仅当)对象具有复制构造函数时,如何复制对象?
【发布时间】:2018-06-14 05:32:54
【问题描述】:

上下文:我正在尝试记忆模板类的对象。目前,该类是一个深度嵌套的数据结构,其中充满了唯一指针,因此没有复制构造函数(据我所知,因此无法缓存)。但是,将来,如果复制构造函数可用,我想允许记忆。我尝试了以下代码:

// some function here... {
  static std::unordered_map<State, Result> cache;

  return [c, ToValue](State state) {
      if (cache.find(state) != cache.end()) {
        std::cout << "retrieving Literal from cache\n";
        if (std::is_copy_constructible<Result>::value) {
          return cache[state];
        }
      }
      // calculate and return a Result

此代码无法编译,因为 Result 没有复制构造函数。有没有办法解决这个问题?谷歌非常无助。

【问题讨论】:

  • 请发MCVE 显示无法编译的代码
  • 你可以试试if constexpr( std::is_copy_constructible...,但是如果那是假的,你也应该返回一些东西
  • 如果Result 不是可复制构造的,你想返回什么?
  • std::optional 视为返回类型。这样你就可以返回一些东西,以防Result 不可复制。
  • 如果我没看错的话,这一切都与复制结构无关——请在下面查看我的答案。

标签: c++ copy-constructor memoization


【解决方案1】:

我假设您得到的错误是当对象不可复制时无法编译return cache[state];。要解决这个问题,您可以编写:

if constexpr (std::is_copy_constructible<Result>::value) {
      return cache[state];
    }

如果您仍然遇到问题,请发布有错误的MCVE

【讨论】:

    【解决方案2】:

    正如其他人所评论的那样,这个问题定义不明确且有点混乱,但是您是否需要真正复制一个对象才能缓存它?

    实际上,没有。您可以使用std::shared_ptr 在创建者、任何消费者和缓存之间共享对象的所有权。如果没有别的,如果您的对象是一个复杂的对象,这会更有效。它也适用于任何类型的对象,无论是否可复制。

    示例(我将使用 Key 而不是 State,原因很明显)。

    鉴于这些声明:

    class MyKey
    {
        // ....
    };
    
    class MyCacheableObject
    {
        // Constructor
        MyCacheableObject (int a, int b, int c) { ... }
        // ...
    };
    
    static std::unordered_map<MyKey, std::shared_ptr<MyCacheableObject>> cache;  // or std::map
    

    您可以这样做(请注意,还有其他方法可以制作std::shared_ptr,请参阅here):

    std::shared_ptr<MyCacheableObject> CreateCacheableObject (int a, int b, int c)
    {
        return std::make_shared<MyCacheableObject> (MyCacheableObject (a, b, c));
    }
    

    然后,假设您有一个计划用于稍后从缓存中检索对象的密钥,您可以这样做:

    MyKey someKey = ...;
    std::shared_ptr<MyCacheableObject> newObject = CreateCacheableObject (1, 2, 3);
    
    // ... setup / use `newObject` in whatever way is appropriate to your use-case 
    
    cache [someKey] = newObject;
    

    您当然可以通过以下方式从缓存中检索对象(如果它在其中):

    auto retrievedObject = cache.find (someKey)
    if (retrievedObject != cache.end())
        ...
    

    所以这个问题根本不是关于对象是否可复制的问题。这是关于(共享)所有权,std::shared_ptr 会为您处理所有这些,您实际上不必考虑它。哎呀。

    有一个现场演示,表明这一切都可以编译,here

    【讨论】:

    • 非常感谢您的详细回复!但是,使用共享指针不会允许修改缓存中的对象吗?该函数可以返回一个指向对象的共享指针,并缓存另一个指向它的共享指针;然后,使用该函数的人可能会改变对象,导致缓存现在变坏。
    • 当然可以。我对您的申请一无所知,因此只有您可以决定这是否真的对您来说是个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 2010-12-22
    • 2016-10-10
    • 1970-01-01
    • 2011-01-20
    • 2015-12-05
    相关资源
    最近更新 更多