gpt4 book ai didi

c++ - 具有算术运算返回类型的 valarray

转载 作者:IT老高 更新时间:2023-10-28 23:21:38 26 4
gpt4 key购买 nike

当我用 valarray 写一个简单的算术表达式时并将结果分配给 auto当我尝试在 gcc 上访问结果时出现段错误。

#include <iostream>
#include <valarray>
using std::ostream; using std::valarray;
ostream& operator<<(ostream&os, const valarray<double>&vs) {
os << "[";
for(auto&v : vs) os << v << " ";
return os << "]";
}
int main() {
valarray<double> a{ 1.0, 2.0, 3.0, 4.0 };
std::cout << "a: " << a << "\n";
valarray<double> b{ 2.0, 4.0, 6.0, 8.0 };
std::cout << "b: " << b << "\n";
valarray<double> c{ 2.0, 1.5, 0.5, 0.25 };
std::cout << "c: " << c << "\n";
valarray<double> x = ( a + b ) / 2;
std::cout << "x: " << x << "\n";
// this still works:
auto y = ( a + b ) / 2;
// The following will result in a segfault:
std::cout << "y:" << y << "\n";
}

reference表示实现可以选择算术运算重载的返回类型可能不是 valarray -value 但“表现得像它”的东西:

The operators returning a valarray by value are allowed to return an object of a different type instead. Such a type is required to be implicitly convertible to valarray and be supported as argument for all functions taking valarray& arguments. This allows copy-on-write implementations.

好吧,我的 operator<<应该要求那种“隐式转换”,不是吗?

那么为什么会出现段错误?

$ ./valarray01.cpp.x
a: [1 2 3 4 ]
b: [2 4 6 8 ]
c: [2 1.5 0.5 0.25 ]
x: [1.5 3 4.5 6 ]
Segmentation fault (core dumped)

gcc version 6.2.0 20160901 (Ubuntu 6.2.0-3ubuntu11~14.04)

当我尝试 clang(在 linux 上,所以可能是 gcc 的 stdlib)时,我对此持怀疑态度......它有效:

clang version 3.9.1-svn288847-1~exp1 (branches/release_39)

$ ./valarray01.cpp.x
a: [1 2 3 4 ]
b: [2 4 6 8 ]
c: [2 1.5 0.5 0.25 ]
x: [1.5 3 4.5 6 ]
y:[1.5 3 4.5 6 ]

好吧,在我提交 gcc-bug 之前……我做错了什么吗?是我的auto邪恶的?还是真的是 gcc?

最佳答案

这是因为 GCC 的 valarray实现使用 Expression Templates避免为算术表达式的中间结果创建临时对象。表达式模板和 auto不要混合好。

发生的是 ( a + b )不立即执行乘法,而是创建一个“闭包”对象,该对象具有对 a 的引用和 b .实际乘法将被延迟,直到在需要结果的上下文中使用闭包。接下来,表达式的其余部分 ( a + b ) / 2创建第二个闭包对象,该对象包含对第一个闭包对象的引用,以及对值 2 的引用.然后使用第二个闭包对象来初始化一个由 auto 推导出的类型的变量。 :

auto y = ( a + b ) / 2;

所以 y是一个闭包对象,它引用了第一个闭包和 int有值 2 .但是,第一次关闭和int value 都是临时变量,在语句末尾超出范围。这意味着 y有两个悬空引用,一个临时关闭和一个临时 int .当您尝试使用 ycout声明它被转换为 valarray<double>它试图评估乘法和除法的结果。该评估遵循悬空引用并尝试访问不再存在的临时对象。这意味着未定义的行为。

我正在为 GCC 开发一个补丁,这将有助于使这样的代码更不容易出错(对于 Bug 83860 ),尽管结合 auto 仍然很脆弱带有表达式模板。

如果您不使用 auto,代码可以正常工作即

std::valarray<double> y = (a+b)/2;

这里的表达式模板在临时对象超出范围之前被评估,因此没有悬空引用。

这个特殊的例子可以通过编译 -fstack-reuse=none 来“工作”。这禁用了重用临时对象使用的堆栈空间的优化。这意味着悬空引用在其生命周期结束后仍可用于访问临时对象。这只是一个创可贴,而不是真正的解决方案。真正的解决方案是不要将表达式模板和 auto 混合使用。 .

关于c++ - 具有算术运算返回类型的 valarray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42726804/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com