【发布时间】:2020-09-22 09:32:39
【问题描述】:
我是 C++ 新手,来自 python/kotlin 背景,所以在理解这里的幕后发生的事情时遇到了一些麻烦......
问题
我使用所需参数调用calculateWeights(公共)方法,然后调用一系列方法,包括conjugateGradientMethod(私有),并且应该返回一个双精度向量。 conjugateGradientMethod 将双精度向量返回到 calculateWeights 就好了,但 calculateWeights 不会将其返回给它的调用者:
代码
calculateWeights 的调用点:
Matrix cov = estimator.estimateCovariances(&firstWindow, &meanReturns);
cout << "before" << endl; // this prints
vector<double> portfolioWeights = optimiser.calculateWeights(&cov, &meanReturns);
cout << "after" << endl; // this does not print
这里是calculateWeights:
vector<double> PortfolioOptimiser::calculateWeights
(Matrix *covariances, vector<double> *meanReturns) {
vector<double> X0 = this->calculateX0();
Matrix Q = this->generateQ(covariances, meanReturns);
vector<double> B = this->generateB0();
vector<double> weights = this->conjugateGradientMethod(&Q, &X0, &B);
cout << "inside calculateWeights" << endl;
print(&weights); // this prints just fine
cout << "returning from calculateWeights..." << endl; // also prints
return weights; //this is where the SIGABRT shows up
输出
输出看起来像这样(我已经检查过了,它输出的权重在数字上确实是正确的):
before
inside calculateWeights
1.78998
0.429836
-0.62228
-0.597534
-0.0365409
0.000401613
returning from calculateWeights...
然后什么都没有。
我很欣赏这是不理想的 printf 调试,因此我使用 Cion 的调试器找到以下内容:
当我使用 CLion 的调试器时
我在 conjugateGradient 方法和 calculateWeights 方法的返回值上设置了一个断点。调试器通过第一个就好了。在我跨过 calculateWeights 的返回后,它向我显示了一个 SIGABRT,并出现以下错误:
Thread 1 "markowitzportfoliooptimiser" received signal SIGABRT, Aborted.
__gnu_cxx::new_allocator<std::vector<double, std::allocator<double> > >::deallocate (this=0x6, __p=0x303e900000762) at /usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/ext/new_allocator.h:129
这可能是错误的,但我第一次尝试理解是我已经超出了vector<double> weights 的大小?它只有 6 双倍长,在下面的循环之后我从不附加任何东西。这就是它在conjugateGradientMethod 内部的创建方式:
如何在conjugateGradientMethod中创建权重
vector<double> weights= vector<double>(aSize);
for (int i = 0; i < aSize; i++) {
weights[i] = aCoeff * a->at(i) + bCoeff* b->at(i);
}
我尝试过的事情
- 初始化
calculateWeights中的双权重向量并将指向它的指针传递给conjugateGradientMethod。结果相同。 - 在
calculateWeights和conjugateGradientMethod类上都有一个公共属性,并让它为其分配权重(因此两个函数都返回 void)。结果相同。
更一般地说,我之前在传递两个函数的返回值时遇到过这种问题。 (如果这有意义?)即从私有方法到公共方法,再到公共方法的调用点。
如果在这种情况下对 SIGABRT 提供任何建议,我将不胜感激,我读过它是在 abort() 向调用进程发送 SIGABRT 信号时,但我不确定如何在此示例中使用它。
另外,我对任何其他有助于在未来避免这种情况的风格/最佳做法都充满信心
编辑:找到解决方案
经过大量工作后,我安装并运行了 Ubuntu 20.04 LTS,因为我无法让 Address Sanitizer 和 Valgrind 在 Windows 10 上通过 WSL 工作(第一次在 Linux 上 - 我有点喜欢它)。
现在使用 Address Sanitizer,我可以看到我在两个独立帐户的双精度向量中写入了太多元素,与 @Lukas Matena 正确发现的 weights 向量无关。令人困惑的是,这早在它到达上面的 sn-ps 之前。
如果将来有人发现这个,这些对我有很大帮助:
【问题讨论】:
-
我看不出这些 sn-ps 有什么问题。我的猜测是某个地方的堆栈损坏,以某种方式恰好触发调用
abort()的断言失败。如果您的编译器支持,请尝试启用 AddressSanitizer,或者在 valgrind 下运行。 -
看来你是在 Linux/Unix 下,安装 valgrind 并用它运行你的程序,它会提示你无效的内存访问/释放/删除/...
-
明智的选择是您的代码中有未定义的行为。第一步,在这种情况下……您是否完全打开了编译器警告并解决了所有问题? (感谢我在打字时输入的评论,是的,在 valgrind 中运行你的程序,它会带你犯错误)
-
感谢大家的快速回复。我正在通过 cygwin 安装 g++ 的 Windows 电脑上运行。我目前正在为 Windows 上的 clion 安装并找出 valgrind。我刚刚打开了编译器警告,我看到的唯一警告与未使用的变量有关[对于我即将实现的功能]。再次感谢大家。
-
原来我使用的 CLion 版本(或更新版本)有一个错误,因为我在 PC 上,所以不允许 valgrind 所需的 WSL:youtrack.jetbrains.com/issue/CPP-11852 我现在到地址消毒剂...
标签: c++ function return clion sigabrt