Эйген назвал доступ к векторному сегменту - PullRequest
0 голосов
/ 10 июля 2020

Я хотел бы создать собственный векторный класс Eigen, в котором были бы именованные ссылки на определенные c сегменты (или блоки для матриц). Это должно позволить мне сразу изменять определенные c части вектора без необходимости запоминать указанные c индексы, что, на мой взгляд, приводит к более удобочитаемому коду при работе с большими векторами / матрицами. Следуя некоторым советам в документации Eigen, я придумал следующую демонстрационную реализацию:

#include "Eigen/Core"
#include <iostream>

struct State : public Eigen::Matrix<double,12,1>{
    static constexpr unsigned int SIZE = 12;
    using data_t = Eigen::Matrix<double,SIZE,1>;

    Eigen::Ref<Eigen::Vector3d> pos;// Same problem using Eigen::VectorBlock<data_t,3>
    Eigen::Ref<Eigen::Vector3d> ang;
    Eigen::Ref<Eigen::Vector3d> vel;
    Eigen::Ref<Eigen::Vector3d> ang_vel;

    State(const Eigen::Vector3d& pos, const Eigen::Vector3d& ang, const Eigen::Vector3d& vel, const Eigen::Vector3d& ang_vel)
    : State(){
        this->pos = pos;
        this->ang = ang;
        this->vel = vel;
        this->ang_vel = ang_vel;
    }

    State() : State(data_t::Zero()){}

    // This constructor allows you to construct State from Eigen expressions
    template<typename OtherDerived>
    State(const Eigen::MatrixBase<OtherDerived>& other)
    : data_t(other), pos(this->segment<3>(0)), ang(this->segment<3>(3)), vel(this->segment<3>(6)), ang_vel(this->segment<3>(9)){}

    // This method allows you to assign Eigen expressions to State
    template<typename OtherDerived>
    State& operator=(const Eigen::MatrixBase<OtherDerived>& other)
    {
        this->data_t::operator=(other);
        return *this;
    }
};

State createState(){
    State x;
    x.pos = Eigen::Vector3d(1.0,1.0,1.0);
    return x;
}

int main(){
    State x = createState();
    std::cout << x.pos << std::endl;
    State dx;
    dx.pos = x.pos/2;
    std::cout << dx.pos << std::endl;
    return 0;
}

Этот код отлично работает в режиме Release (с включенной оптимизацией) и печатает

1, 1, 1 0,5, 0,5, 0,5

Однако, когда я включаю режим отладки (без оптимизаций и добавленных символов отладки), он печатает что-то вроде

-9.25596e + 61, -9.25596 е + 61, 0 -4.62798e + 61, -4.62798e + 61, -4.62798e + 61

Я использую MSV C Build tools 2019 на ноутбуке windows 10 для компиляции и запуска этого примера. При более внимательном изучении с помощью отладчика кажется, что данные в самом векторе все еще не повреждены, однако названные ссылки теперь указывают на разные места в памяти (висячие указатели). Также важно отметить, что такое поведение наблюдается только для State, возвращаемого другой функцией. Если State построен внутри основной функции, все работает так, как ожидалось.

Я нашел решение этой проблемы, которое опишу в ответе ниже, но хотел узнать, не знает ли кто-нибудь, кто более знаком с Eigen внутренности могут объяснить это и / или предложить лучшее решение.

Обновление: Я только что протестировал приведенный выше код на другом компьютере (Linux), используя G CC 6.4.0 а там все нормально работает. Так что это может быть связано с компилятором.

1 Ответ

0 голосов
/ 10 июля 2020

Я обнаружил, что предоставление настраиваемого (иначе созданного по умолчанию) конструктора копирования и конструктора перемещения решает указанную выше проблему.

State(const State&)
: data_t(other), pos(this->segment<3>(0)), ang(this->segment<3>(3)), vel(this->segment<3>(6)), ang_vel(this->segment<3>(9)){
    // Default copy constructor causes dangling references in debug mode.
}
State(State&& other)
: data_t(std::move(other)), pos(this->segment<3>(0)), ang(this->segment<3>(3)), vel(this->segment<3>(6)), ang_vel(this->segment<3>(9)){
    // Default move constructor causes dangling references in debug mode.
}

Из-за этих изменений компилятор пожаловался, что оператор присваивания копии был удален по умолчанию , поэтому мне также нужно было добавить реализацию для этого оператора (это было необходимо только в более сложном сценарии, чем простая демонстрация выше):

State& operator=(const State& other){
    this->data_t::operator=(other);
    return *this;
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...