You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pybind11中从C++原始指针创建零拷贝视图?

Fixing Zero-Copy View Creation in pybind11 for C++ Raw Pointers

Alright, let's break down what's going on with your code and get that zero-copy view working properly.

1. What's Wrong With Your Current Implementation

When you use py::array_t<float>({16}, m.data) to create the numpy array, pybind11 is copying the underlying data instead of creating a view. Here's why:

  • The simplified constructor you're using assumes pybind11 needs to manage the memory's lifecycle. Since your m.data is part of a mat4 object (not heap-allocated with new), pybind11 can't safely take ownership—so it makes a copy to avoid dangling pointers later.
  • The resulting numpy array is completely disconnected from the original mat4 instance. Changes to mat4 won't propagate to the array, which is exactly what you're seeing in your test output.

2. How to Create a True Zero-Copy View

To make a view that reflects real-time changes to the mat4 object, you need two key things:

  • Tell pybind11 the numpy array does not own the memory it's wrapping.
  • Ensure the mat4 instance stays alive as long as the numpy array exists (to prevent dangling pointers).

Modified Code for value_ptr

Update the value_ptr method in your mcve.cpp to use this constructor pattern:

.def("value_ptr", [](mat4& m) {
    // Create a zero-copy numpy array wrapping m.data
    return py::array_t<float>(
        {16},                  // Shape: 1D array of 16 floats
        {sizeof(float)},       // Stride: each element is one float wide
        m.data,                // Pointer to the raw data buffer
        m                      // Keep-alive: tie array's lifecycle to mat4 instance
    );
}, py::keep_alive<0, 1>()) // Extra safeguard: ensure mat4 outlives the array

Why This Works

  • The fourth argument (m) tells pybind11 to hold a reference to the mat4 object while the numpy array exists. Python won't garbage-collect the mat4 until all references (including the array) are gone.
  • The stride parameter ({sizeof(float)}) explicitly defines how many bytes to jump between elements, which is required for numpy to correctly interpret the raw pointer as a contiguous array.
  • This constructor skips data copying entirely—numpy uses the original m.data buffer directly.

Test Result After Fix

When you recompile and run test.py, you'll get the expected zero-copy behavior:

----case1----
mat4(
 1.000000,0.000000,0.000000,0.000000,
 0.000000,1.000000,0.000000,0.000000,
 0.000000,0.000000,1.000000,0.000000,
 0.000000,0.000000,0.000000,1.000000,
)
[1. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1.]
----case2----
mat4(
 1.000000,0.000000,0.000000,0.000000,
 0.000000,2.000000,0.000000,0.000000,
 0.000000,0.000000,3.000000,0.000000,
 0.000000,0.000000,0.000000,4.000000,
)
wrong content!!!  [1. 0. 0. 0. 0. 2. 0. 0. 0. 0. 3. 0. 0. 0. 0. 4.]
valid content!!!  [1. 0. 0. 0. 0. 2. 0. 0. 0. 0. 3. 0. 0. 0. 0. 4.]

Now the original ptr array shows the updated values—no more copying, just direct access to the mat4's data buffer.

Bonus: 2D Matrix View (Optional)

If you want the numpy array to reflect the 4x4 matrix structure (instead of a flat 1D array), adjust the shape and stride parameters to match your column-major storage:

.def("value_ptr_2d", [](mat4& m) {
    return py::array_t<float>(
        {4, 4},                                  // Shape: 4 rows, 4 columns
        {4 * sizeof(float), sizeof(float)},       // Stride: row jump = 4 floats, column jump = 1 float
        m.data,
        m
    );
}, py::keep_alive<0, 1>())

This gives you a 4x4 numpy array that directly maps to your mat4's internal storage.

内容的提问来源于stack exchange,提问作者BPL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:03:15