Этот вопрос может касаться серьезного UB. Я ищу объяснение и решение по этому делу.
Наконец, мы с командой столкнулись со странной (но объяснимой) проблемой, с которой мы не смогли найти подобных проблем в Интернете. и нам нужны некоторые ответы об этом.
- Мы понимаем проблему перераспределения вектора (при изменении размера). Однако мы не можем понять, почему указатель «this» не обновляется автоматически при каждом изменении.
- Есть ли способ обновить указатель «this» на правильный адрес?
- Что такое лучший и самый общий c способ решения следующей проблемы (наше предложение можно найти в конце этого поста, но мы ищем более элегантные / обобщенные c способы)?
Дело:
У нас есть класс [TesrClass] и векторный контейнер для этого класса. Одна из функций TestClass, приводящая к перераспределению контейнера векторов (во время push / emplace), и переход к некоторым следующим шагам после этого, которые используют переменные / функции членов класса [UB?].
Проблема:
После перераспределения «этот» объект больше не действует внутри этой функции-члена [Аллилуйя]. Это ожидаемое поведение? [Проверено с g ++ & clang - Ubuntu 16.04].
Демонстрация кода:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class TestContainer;
class TestClass {
public:
TestClass(int n, TestContainer *tcontainer) {
num = n;
container = tcontainer;
}
void func();
private:
int num;
TestContainer *container;
void class_member_function();
};
class TestContainer {
public:
vector<TestClass> tc_vec;
};
void TestClass::class_member_function() {
cout << "Class Member Function:" << endl << endl;
cout << "Container Vector Data:" << endl;
for (auto& elem : container->tc_vec) {
cout << "Object Address: " << &elem << " | Number: " << elem.num << endl;
}
cout << endl;
cout << "Function Data:" << endl;
cout << "Object Address: " << this << " | Number: " << num << endl;
cout << "=====================" << endl;
}
void TestClass::func() {
class_member_function();
/*
* Example Print:
* =============================================
* Class Member Function:
* Container Vector Data:
* Object Address: 0x22fcc20 | Number: 10
* Function Data:
* Object Address: 0x22fcc20 | Number: 10 // As expected.
* =============================================
*/
container->tc_vec.emplace_back(4, container);
class_member_function();
/*
* Example Print:
* =============================================
* Class Member Function:
* Container Vector Data:
* Object Address: 0x22fd050 | Number: 10 // Address changed as expected, as a result of the vector's reallocation (reserve will solve this problem, but not a generic solution).
* Object Address: 0x22fd060 | Number: 4
* Function Data:
* Object Address: 0x22fcc20 | Number: 0 // Pay attention!! Address didn't change, and doesn't exists in the vector anymore.
* =============================================
*/
}
int main() {
TestContainer container;
container.tc_vec.emplace_back(10, &container);
container.tc_vec[0].func();
return 0;
}
Наши предложения:
- Используйте резерв и проверьте емкость (Мы являемся пытаясь избежать этого, из-за общих c причин и более разумного управления ресурсами).
- Используйте интеллектуальные указатели внутри вектора (
vector<shared_ptr<TestClass>>
). - Вместо использования прямого доступа к классу члены, сохраните свойство идентификатора класса [в предыдущем примере] не существует в функции локально (до изменения), затем ищите его каждый раз в векторе контейнера, чтобы получить доступ к правильному месту в памяти [Still UB?].
- Используйте
std::list
вместо std::vector
. - Добавьте обновленное «this» в функцию wile (возможно ли это?).