使用 valuePtr() 等为 Eigen3 稀疏矩阵分配空间

Using valuePtr() etc to allocate space for Eigen3 SparseMatrix

本文关键字:分配 空间 Eigen3 valuePtr 等为 使用      更新时间:2023-10-16

我正在尝试使用这样的malloc初始化Eigen::SparseMatrix A

A.valuePtr() = static_cast<T*>(std::malloc(nnz*sizeof(T)));
A.innerIndexPtr() = static_cast<int*>(std::malloc(nnz*sizeof(int)));

但我收到错误

error: lvalue required as left operand of assignment

对于这两个语句。如果很重要,包含行的函数会通过引用Eigen::SparseMatrix<T, Eigen::RowMajor>

谁能帮我解决这个问题?我正在使用 g++ 5.2。

编辑:类SparseMatrix的函数valuePtr

inline Scalar* valuePtr() { return &m_data.value(0); }

Scalar是一个模板参数。 m_dataCompressedStorage 类型的受保护变量,其方法value(size_t i)返回对其内部数据数组的第 i 个成员的引用

 inline Scalar& value(size_t i) { return m_values[i]; }

因此,我得出结论,valuePtr()返回数组第一个元素的地址。然后,我应该能够通过malloc为该数组分配空间。

如果有人感兴趣,我包含一个链接以供参考 - 请参阅84和131之后的行。Eigen3 稀疏矩阵类

问题很可能是由于您尝试将对象分配给方法!

您的行相当于: A.valuePtr() = Sometype_Pointer;A.valuePTR()将调用对象 A 的 Eigen::SparseMatrix::valuePTR 方法(函数)。

如果此方法返回指针 ( T* A::valuePtr() ),则返回的指针不是您想要的! 该方法将返回一个 rvalue; 值不是不是 A 中包含的指针的左值,而是指针的临时副本
你不能直接给它分配任何东西,就像你不能触摸电视屏幕上的人一样。

做了一个巨大的假设,即您尝试执行我上面描述的操作,除非该方法如下所示,否则这是不可能的:

T ** Eigen::SparseMatrix::valuePTR()
{
    return &T;
}
*A.valuePtr() = static_cast<T*>(std::malloc(nnz*sizeof(T)));

但是,请注意,对于 c++ 对象来说,使用 malloc 被认为是非常非常过时的,像这样一行的东西会更正确 *A.valuePtr() = static_cast(new T[nnz]));

[编辑/]

老实说,我正在努力理解您的代码应该完成什么。而大多数人(包括我自己)都不会熟悉这个"本征"类。虽然我认为你可能非常误解它应该如何使用。

您能否提供文档链接,或如何创建/使用此类的示例?

[编辑2/]

经过一些研究,我遇到了这篇文章以及这个问题,您是否需要使用MappedSparseMatrix。

[编辑3/]

inline Scalar* valuePtr() { return &m_data.value(0); }将返回一个右值指针。这不是m_data中保存的对象,也不是内部使用的指针。它是指向现有对象的指针的临时副本,试图说"使此临时副本指向其他内容"是没有意义的。

inline Scalar& value(size_t i) { return m_values[i]; } 在这种情况下,该方法返回对对象的引用,引用不是指针 - (尽管&经常让人们感到困惑)。
引用可以理解为原始对象,不需要取消引用引用。请考虑以下事项。

int A;
int * A_p = &A;
int & A_r = A;
int & A_r_2 = *A_p;
//de-reference the pointer (to create a reference)
*A_p = 10;  //A == 10
//Assign directly to A (via the reference)
A_r = 12; // A == 12
//assign directy to A (via the reference to A, that was taken from A_p
A_r_2 = 15; // A == 15
//attempt to de-reference a reference
*A_r = 10; //ERROR, A_r is not a pointer.

简而言之,返回的引用不是指向对象(已存在)的指针,而是对象。这将允许您将对象设置为某些内容,或使用 . 运算符调用对象上的方法,但是您不能重新分配已经存在的内容,因此是一个错误。

请考虑阅读这篇文章,了解 rvale 和 lvalue 在理解 rvalue 和 lvalue 方面的区别C++

在@John巴格曼告诉我我对右值和左值的看法是错误的之后,我想了想并尝试了一下:

class A
{
    char* str;
public:
    // This function returns a literal (constant) of type char* 
    // (just an address), not a pointer variable
    char* getstr() {
        return str;
    }
    char getchar(const int i) const {
        return str[i];
    }
};
int main()
{
    A a;
    // the RHS can't be assigned to a literal, we need a variable in the LHS
    a.getstr() = static_cast<char*>(malloc(10*sizeof(char)));   // ILLEGAL!
    // this assigns the address contained in str to mstr.
    char* mstr = a.getstr();
    // after this, mstr will have nothing to do with A::str; the former 
    // will have been re-assigned to a different address
    mstr = static_cast<char*>(malloc(10*sizeof(char)));
    for(int i = 0; i < 9; i++)
        mstr[i] = '0';
    mstr[9] = '';
    // The following line segfaults as no storage has been allocated to A::str
    cout << a.getchar(1) << endl;   // runtime error!
    free(mstr);
    return 0;
}

现在我明白了函数SparseMatrix::valuePtr(),像A::getstr()一样,返回某种地址类型的文字;它不返回左值。试图将某些东西(在本例中为 malloc 返回的内存块的开头地址)分配给文字(在本例中为像 0x233ff554 这样的地址)是没有意义的。我想我现在明白它是如何工作的。谢谢@John巴格曼!