当相关的 ctor 是私有的时,如何 return 堆上的 class 实例?

How to return a class instance on the heap, when the relevant ctor is private?

假设我有这个结构

struct MyStruct {

  static MyStruct Create(int x) {
    return { x*2, x>3 };
  }

  MyStruct(const MyStruct& c) = delete;  // no copy c'tor

private:
  MyStruct(int a_, bool b_) : a(a_), b(b_) {}  // private c'tor -- can't use new

  const int a;
  const bool b;
};

编辑: 我删除了复制构造函数。这是一些 类 我在我的代码库中没有复制 c'tors 的简化示例。

我可以像这样在堆栈上获取一个实例:

int main() {
  auto foo = MyStruct::Create(2);
  return 0;
}

但是假设我需要一个指针来代替(或者 unique_ptr 可以),而且我无法更改 MyStruct 的实现,我该怎么做?

您可以将 MyStruct 包装在另一个具有 MyStruct 成员的 class 中。这是它的最小版本:

class Wrapper {
public:
    MyStruct ms;
    Wrapper(int x) : ms(MyStruct::Create(x)) { }
};

你可以这样使用:

int main() {
  MyStruct::Create(2);
  std::make_unique<Wrapper>(2);
}

此代码will not trigger any copies nor moves - because of copy elision (see: What are copy elision and return value optimization?).

然后您可以将您喜欢的任何其他构造函数和方法添加到此类包装器中,可能会将一些方法调用转发给 ms 成员。有些人可能会选择 ms 受保护或私有。

这是您要找的吗?

auto baz  = std::make_unique<MyStruct>( MyStruct::Create(2) );  // unique pointer

另一种方法:

  struct ChildStruct : public MyStruct {                                                                                  
      ChildStruct(int x) : MyStruct(MyStruct::Create(x))                             
      {}                                                                             
                                                                                     
  };                                                                                 
                                                                                     
  int main() {                                                                       
    MyStruct *foo1 = new ChildStruct(2);                                             
    return 0;                                                                        
  }  

C 风格的解决方案。我不确定这不是 UB,但对于具有 2 个整数字段的简单结构,它应该可以工作。

int main() {                                                                    
    auto foo = MyStruct::Create(2);                                               
                                                                                  
    MyStruct *p = (MyStruct*)malloc(sizeof(MyStruct));                            
    memcpy(p, &foo, sizeof(MyStruct));                                            
    //...
    free(p);
    return 0;                                                                     
}

评论而不是答案,以避免给未来的读者造成混淆。

I can get an instance on the stack like so:

int main() {
  auto foo = MyStruct::Create(2);
  return 0;
}

请注意,这仅适用于 C++17 并保证复制省略,而程序格式错误是 C++14,即使复制 可能 被省略,foo 的初始化是从临时文件的复制初始化(在 C++17 中:临时文件永远不会 实现 )。