pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.09k stars 2.05k forks source link

[BUG]: Const Eigen::VectorXd class member changes #5034

Closed markojukic closed 4 months ago

markojukic commented 4 months ago

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

2.11.1

Problem description

Why does the code below give two different outputs: one from inside the constructor and one after the constructor?

#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>

namespace py = pybind11;

class Test {
public:
    const Eigen::VectorXd &x;
    explicit Test(const Eigen::VectorXd &x) : x(x) {
        std::cout << this->x.transpose() << std::endl;
    }
};

void test(const Eigen::Ref<const Eigen::VectorXd> &x) {
    Test t(x);
    std::cout << t.x.transpose() << std::endl;
}

PYBIND11_MODULE(test_module, m) {
    m.def("test", &test);
}

When I run the test_module.test function, I get:

>>> import numpy as np
>>> from test_module import test
>>> test(np.ones(5))
1 1 1 1 1
 6.9529e-310 2.47033e-323  6.9529e-310 5.53094e-164 4.94066e-324

Here's my CMakeLists.txt

cmake_minimum_required(VERSION 3.28)
project(test_project)

set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED 20)

# Get Python_EXECUTABLE
execute_process(
        COMMAND bash -c "source ${CMAKE_SOURCE_DIR}/.env/bin/activate && which python"
        OUTPUT_VARIABLE Python_EXECUTABLE
        RESULT_VARIABLE exit_status
        ERROR_VARIABLE stderr
        OUTPUT_STRIP_TRAILING_WHITESPACE
)

if (NOT exit_status EQUAL 0)
    message(FATAL_ERROR ${stderr})
endif()

# Get pybind11_DIR
execute_process(
        COMMAND ${Python_EXECUTABLE} -c "import pybind11; print(pybind11.get_cmake_dir())"
        OUTPUT_VARIABLE pybind11_DIR
        RESULT_VARIABLE exit_status
        ERROR_VARIABLE stderr
        OUTPUT_STRIP_TRAILING_WHITESPACE
)

if (NOT exit_status EQUAL 0)
    message(FATAL_ERROR ${stderr})
endif()

# Set up Eigen
include(FetchContent)
FetchContent_Declare(
        eigen
        GIT_REPOSITORY  https://gitlab.com/libeigen/eigen.git
        GIT_TAG         3147391d946bb4b6c68edd901f2add6ac1f31f8c # v3.4.0
)
FetchContent_MakeAvailable(eigen)

find_package(Python 3.11.7 EXACT COMPONENTS Interpreter Development NumPy REQUIRED)
find_package(pybind11 2.11.1 EXACT CONFIG REQUIRED)
find_package(Eigen3 3.4.0 EXACT REQUIRED)

pybind11_add_module(test_module test_module.cpp)
target_link_libraries(test_module PUBLIC Eigen3::Eigen)
set_target_properties(test_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})

Reproducible example code

No response

Is this a regression? Put the last known working version here if it is.

Not a regression

markojukic commented 4 months ago

My bad, I think that a temporary object was being created and passed to the constructor. So I had a dangling reference. I've switched to using Eigen::Ref instead of regular references.