【问题标题】:Possible run-time problems arising from moving temporary object to a heap allocated object?将临时对象移动到堆分配对象时可能出现的运行时问题?
【发布时间】:2018-11-18 04:10:40
【问题描述】:

这是一个非常复杂的示例,可能很少见,但我在执行以下操作时遇到了问题:

class MyClass{
public:
SubClass1 object1; //has pointers/smart-pointers to objects that have pointers to SubClass2
SubClass2* object2; //has pointers/smart-pointers to objects that have pointers/smart-pointers to SubClass1
MyClass(){ object2 = new SubClass2(&object1); }; //SubClass2 constructor establishes the relationship between object1 and object2 pointed-to-objects. 
};
/*....*/
MyClass* ptr = new MyClass(std::move(MyClass()));

我发现 object2 中的一些指针无效。我很想分享 SubClass1 和 SubClass2 的定义,但不幸的是我不允许分享这段代码。

我的问题是,为了防止将临时对象移动到新的堆分配对象时出现问题,类对象是否必须满足某些检查表? 有什么方法可以预先知道移动操作是否会失败?

原来的问题是写错了:

std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(MyClass());

将我的所有 shared_ptr 实例更改为通过 make_shared 而不是 new 构建时。我最终将问题缩小到原始指针、std::move 和临时右值引用。

做的时候:

std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();

效果很好。

奇怪的是,以下没有问题:

MyClass stack_obj{};
MyClass* ptr = new MyClass(std::move(stack_obj));

这似乎是特定于将临时对象移动到堆中的东西?

我还发现,如果我将 object1 改​​为 SubClass1 的指针,我也没有任何问题。 即

class MyClass{
public:
SubClass1* object1;
SubClass2* object2; 
MyClass(){ object1 = new SubClass1(); object2 = new SubClass2(object1); };
};
/*....*/
MyClass* ptr = new MyClass(std::move(MyClass())); //worked fine

我能想象的唯一问题是由于在堆栈上为临时对象 MyClass() 创建了 object1,然后在指针分配期间将 object1 从本地堆栈移动到堆中出现了问题。

为了完成,这些是我能够为原始课程复制相同问题的其他方法:

template <class... Args>
std::shared_ptr<MyClass> make_shared_test(Args&& ... args)
{
    return std::shared_ptr<MyClass>(new MyClass(std::forward<Args>(args)...));
}

MyClass&& forward_test(MyClass&& param){
    return static_cast<MyClass&&>(param);
}

/*....*/
MyClass* obj1(new MyClass(std::move(MyClass())));
std::shared_ptr<MyClass> obj2 = make_shared_test(MyClass());
std::shared_ptr<MyClass> obj3 = std::shared_ptr<MyClass>(new MyClass(forward_test(MyClass())));
std::shared_ptr<MyClass> obj4 = std::shared_ptr<MyClass>(new MyClass(std::move(MyClass())));
std::shared_ptr<MyClass> obj5(new MyClass(std::move(MyClass())));

【问题讨论】:

  • 你能提供一个minimal, complete and verifiable example 吗?答案可能取决于数据成员的内部结构。
  • 在第一段代码中,您调用复制或移动构造函数,该构造函数具有其默认编译器生成的定义,我几乎可以肯定它会做一些您可能不希望它做的事情。指针操作可能存在问题。但首先,如果你按照@Sander De Dycker 的建议去做就好了。
  • 我很想分享 SubClass1 和 SubClass2 的定义,但遗憾的是我不允许分享此代码。 这不是必需的。只需提供类似于关系的类。

标签: c++ stack heap-memory temporary-objects


【解决方案1】:

问题是我忘记了 SubClass1 上的移动构造函数(规则 5)。因此,编译器实际上会复制类而不是移动它,一旦为 SubClass1 调用析构函数,它就会切断 object1 和 object2 之间的关系,从而导致未定义的行为。

感谢您的宝贵时间,也很抱歉浪费您的时间!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-14
    • 2020-04-26
    • 1970-01-01
    • 2011-12-27
    相关资源
    最近更新 更多