Возможные проблемы во время выполнения, возникающие при перемещении временного объекта в выделенный объект кучи? - PullRequest
0 голосов
/ 08 июня 2018

Это очень запутанный пример, который, вероятно, встречается редко, но я столкнулся с проблемами при выполнении следующих действий:

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 и временной ссылки на rvalue.

При выполнении:

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

Единственная проблема, которую я мог себе представить, была в том, что object1 был создан в стеке для временного объекта MyClass (), а затем возникла проблема с перемещением 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())));

1 Ответ

0 голосов
/ 08 июня 2018

Проблема была в том, что я забыл конструктор перемещения в SubClass1 (правило 5).Таким образом, компилятор фактически скопировал бы класс вместо того, чтобы перемещать его, и как только деструктор был вызван для SubClass1, он разорвал бы связь между object1 и object2, вызывая неопределенное поведение.

Спасибо за ваше время, иизвините за трату вашего времени!

...