Функция-член класса внутри вектора, активная при переопределении вектора - PullRequest
0 голосов
/ 24 января 2020

Этот вопрос может касаться серьезного UB. Я ищу объяснение и решение по этому делу.

Наконец, мы с командой столкнулись со странной (но объяснимой) проблемой, с которой мы не смогли найти подобных проблем в Интернете. и нам нужны некоторые ответы об этом.

  1. Мы понимаем проблему перераспределения вектора (при изменении размера). Однако мы не можем понять, почему указатель «this» не обновляется автоматически при каждом изменении.
  2. Есть ли способ обновить указатель «this» на правильный адрес?
  3. Что такое лучший и самый общий 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;
}

Наши предложения:

  1. Используйте резерв и проверьте емкость (Мы являемся пытаясь избежать этого, из-за общих c причин и более разумного управления ресурсами).
  2. Используйте интеллектуальные указатели внутри вектора (vector<shared_ptr<TestClass>>).
  3. Вместо использования прямого доступа к классу члены, сохраните свойство идентификатора класса [в предыдущем примере] не существует в функции локально (до изменения), затем ищите его каждый раз в векторе контейнера, чтобы получить доступ к правильному месту в памяти [Still UB?].
  4. Используйте std::list вместо std::vector.
  5. Добавьте обновленное «this» в функцию wile (возможно ли это?).
...