我是一个刚接触C++的新手,来自于pythonkotlin的背景,所以在理解背后发生的事情时遇到了一些困难......
问题
我叫 calculateWeights
(public)方法,然后它调用一系列方法,包括 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)。同样的结果。更一般的是,我以前也遇到过这种问题,从两个函数深层传递一个返回值上去。(如果这样说有道理的话?)即从私有方法向上传递到公共方法,再到公共方法的callite。
如果有任何关于SIGABRT在这种情况下的建议,我将感激不尽,我读到的是当 abort()
向调用进程发送SIGABRT信号,但我不知道如何在这个例子中使用这个信号。
另外,我也很想听听其他有助于在未来避免这种情况的风格最佳实践。
编辑:找到解决方案
经过一番努力,我安装并运行了Ubuntu 20.04 LTS,因为我在Windows 10上无法通过WSL让Address Sanitizer和Valgrind工作(第一次在Linux上工作--我有点喜欢它)。
随着地址净化器的工作,我能够看到我在两个不同的账户上向一个双倍的向量写入了太多的元素,这与我的地址净化器无关。weights
矢量,因为@Lukas Matena正确地发现。令人困惑的是,这是在它到达上面的片段之前很久的事情。
如果有人在未来发现这个问题,这些对我帮助很大。
错误信息说,它未能重新分配一个 std::vector<double>
当 calculateWeights
即将返回。这很可能意味着函数中至少有一个局部变量(此时正在被破坏)被破坏了。
你似乎把重点放在了 weights
但既然你提到的尝试都失败了,我宁愿怀疑... X0
或 B
(weights
是也许在那个时候由于返回值的优化,甚至没有deallocated)。)
你可以尝试的事情。
你很可能在某个地方对各自的向量做了坏事,可能是在 calculateX0
或 generateB0
你还没有分享)。它可能是 delete
-的一部分,返回一个临时的引用,而不是一个拷贝,等等。这时的SIGABRT return
是你被发现的地方,但内存损坏问题往往比引起的时间晚。
(我本想把这个做得短一点,作为评论发上去,但作为一个新手我做不到。希望能算作是 "在这种情况下对SIGABRT的建议",其实这也是要求的)。)