传递一个 returns 一个按值向量作为 ublas::element_prod() 参数的函数有什么问题?

What is wrong with passing a function that returns a vector by value as argument of ublas::element_prod()?

我似乎无法理解为什么直接将函数作为参数传递给 ublas::element_prod() 会产生错误的结果。

如果我运行下面的代码:

#include <cmath>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>

namespace ublas = boost::numeric::ublas;

ublas::vector<double>
vector_ln(ublas::vector<double> x) {
    for(auto it = x.begin(); it != x.end(); ++it) {
        (*it) = log(*it);
    }
    return x;
}

int main(void) {
    ublas::vector<double> x(2, 2.0);
    ublas::vector<double> y(2, 10.0);

    std::cout << "x = " << x << std::endl;
    std::cout << "y = " << y << std::endl;

    auto tmp = vector_ln(y);
    auto ret1 = ublas::element_prod(
            x,
            tmp);
    std::cout << ret1 << std::endl;

    std::cout << "x = " << x << std::endl;
    std::cout << "y = " << y << std::endl;

    auto ret2 = ublas::element_prod(
            x,
            vector_ln(y));
    std::cout << ret2 << std::endl;
}

我得到以下输出:

x = [2](2,2)
y = [2](10,10)
[2](4.60517,4.60517)
x = [2](2,2)
y = [2](10,10)
[2](0,4.60517)

谁能告诉我为什么第二种编码风格会产生错误的结果,而没有编译错误?

问题是 ublas 使用表达式模板,其中许多操作的结果是临时的,它只是将 pointer/reference 保留到其输入,并在分配给变量时进行评估。这样做是为了减少不必要的计算和复制。参见 https://en.wikipedia.org/wiki/Expression_templates

但是,随着 C++11 的引入,使用 auto 会产生危险的交互,因为这会保存表达式模板的副本,而不是结果。此表达式模板具有对 vector_ln(y) 返回的临时对象的悬空引用,并导致您遇到的问题。

由于主要问题是与auto的交互,所以解决方案是将其保存为正确的ublas矩阵类型作为element_prod()的结果。它只在第一种情况下有效,因为 none 存储的引用是临时的。