将临时对象移动到堆分配的对象可能会出现 运行 时间问题?
Possible run-time problems arising from moving temporary object to a heap allocated object?
这是一个非常复杂的例子,可能很少见,但我 运行 在执行以下操作时遇到了问题:
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 的定义,但不幸的是我不允许分享这段代码。
我的问题是,class 对象是否必须满足某些检查表,以防止在将临时对象移动到新的堆分配对象时出现问题?
有什么方法可以预先知道移动操作是否会失败?
原问题是因为写错了:
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(MyClass());
当我将所有 shared_ptr 实例更改为通过 make_shared 而不是新实例构建时。我最终将问题缩小到原始指针 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从本地堆栈移动到堆中出现了问题。
为了完成,这些是我能够为原始 class 复制相同问题的其他方法:
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())));
问题是我忘记了 SubClass1 上的移动构造函数(规则 5)。因此,编译器实际上会复制 class 而不是移动它,并且一旦为 SubClass1 调用析构函数,它将切断 object1 和 object2 之间的关系,导致未定义的行为。
感谢您的宝贵时间,抱歉浪费您的时间!
这是一个非常复杂的例子,可能很少见,但我 运行 在执行以下操作时遇到了问题:
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 的定义,但不幸的是我不允许分享这段代码。
我的问题是,class 对象是否必须满足某些检查表,以防止在将临时对象移动到新的堆分配对象时出现问题? 有什么方法可以预先知道移动操作是否会失败?
原问题是因为写错了:
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(MyClass());
当我将所有 shared_ptr 实例更改为通过 make_shared 而不是新实例构建时。我最终将问题缩小到原始指针 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从本地堆栈移动到堆中出现了问题。
为了完成,这些是我能够为原始 class 复制相同问题的其他方法:
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())));
问题是我忘记了 SubClass1 上的移动构造函数(规则 5)。因此,编译器实际上会复制 class 而不是移动它,并且一旦为 SubClass1 调用析构函数,它将切断 object1 和 object2 之间的关系,导致未定义的行为。
感谢您的宝贵时间,抱歉浪费您的时间!