有两个 C++ 项目 - 一个自动交易解决方案和一个单元/回归测试应用程序 - 共享相同的自定义 C++ 库,使用 Qt 框架。这些应用程序以前可以运行,但现在不行了。
在问题发生之前,项目的源代码和库的源代码都没有被更改。任一应用程序上的明显问题与另一个应用程序不同,但根本原因似乎是相同的。
在出现问题之前,我使用默认安装安装了 cygwin(除了添加 g++),清理了解决方案并重新构建,所以我相信 cygwin 安装可能是罪魁祸首。 PATH 变量没有明显的变化。我已经卸载了 cygwin,但问题仍然存在。
运行测试项目时,我收到“读取访问冲突”。 请参阅单元/回归测试项目中的以下代码:
void TradeToolsTest::initTestCase(void)
{
QSharedPointer<UnderlyingAsset> spy = TradeToolsTest::parentLists->getUnderlyingAsset("SPY");
QSharedPointer<QMap<qint64, QSharedPointer<Bar>>> bar30 = QSharedPointer<QMap<qint64, QSharedPointer<Bar>>>(new QMap<qint64, QSharedPointer<Bar>>);
// Convert the bars from JSON to a list of Bars
QSharedPointer<QVector<QSharedPointer<Bar>>> tempBar = api->jsonArrayToItemArray<Bar>(this->mockData["bars"]["spy"]["minute"]["30"].array(), (processJSONObject)TradeTools::Financial::jsonToBar, TradeToolsTest::parentLists);
// Insert the bars into the expected container type
for(QVector<QSharedPointer<Bar>>::iterator itBar=tempBar->begin(), endBar=tempBar->end(); itBar!=endBar; itBar++)
bar30->insert((*itBar)->timestamp, *itBar);
// Add the bars to the asset
spy->addBars(timeframe30, bar30, TradeToolsTest::state, adequateBarCount, TradeToolsTest::parentLists, TradeToolsTest::internalComm, TradeToolsTest::barAdded);
}
bool OQIAsset::addBars(const BarTime barTime, const QSharedPointer<QMap<qint64, QSharedPointer<Bar>>> bar, const QSharedPointer<AppState> appState, bool &adequateBarCount, const QSharedPointer<ParentLists> parentLists, const QSharedPointer<InternalCommunication> internalComm, const BarAdded realBarAdded)
{
return TradeTools::Financial::addBars<OQIAsset>(this, barTime, bar, this->strikeIncrement, appState, adequateBarCount, parentLists, internalComm, realBarAdded);
}
注意:“UnderlyingAsset”类派生自“OQIAsset”类。
以上是解释问题的最小版本代码。
如果我在函数“OQIAsset::addBars”中的 return 语句上设置断点并将“bar.value”添加到监视窗口,QMap::size 属性将具有一些巨大的值,而不是预期的“200”值。当我在调用堆栈上向后移动到调用函数“TradeToolsTest::initTestCase”并将“bar30.value”添加到监视窗口时,QMap::size 属性按预期为“200”。共享对象的指针是同一个地址。
对象类型是相同的,除了被调用函数中的类型是 const - 删除“const”会导致相同的问题 - 我怀疑这是否会解决问题,因为在问题出现之前没有任何代码更改。
交易机器人应用程序的问题是 Qt 库错误地认为 QApplication 在 QWidget 实例化之前尚未实例化。请看以下代码:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Systematic w;
w.show();
return a.exec();
}
Systematic::Systematic(QWidget *parent)
: QMainWindow(parent)
{
Systematic::initUI();
}
void Systematic::initUI(void)
{
Systematic::profitLossChart = new LineChartView;
}
错误:“QWidget:必须在 QWidget 之前构造 QApplication”。
Visual Studio 版本:社区 2022 17.12.3
Qt版本:6.8.1,使用msvc2022_64
操作系统:Windows 11
我已将 Qt 从 6.7.2 升级到 6.8.1,并将 Visual Studio 升级到最新版本,但问题仍然存在。
如上所述,我已经清理并重建了解决方案(包括从项目目录中手动删除 debug / x64 文件夹。),我已经卸载了 cygwin,并且我已经检查了 PATH 变量是否有明显的新条目。
我感谢您能够提供的任何帮助。
这两个应用程序以及库都被编译为调试版本。
该问题是由于将两个可执行项目的“项目属性 -> 配置属性 -> 使用调试库”设置为“否”,我发现完全奇怪的是,此设置成为一个问题,而以前不是这样。
我进一步研究发现:
在“使用调试库”设置为“否”的情况下编译 TradeTools 的调试版本时出现运行时问题可能是由于构建配置与链接或使用的库之间不匹配造成的。这就是为什么这很重要以及它如何影响应用程序:
CRT 库之间不匹配
调试版本通常链接到 C 运行时 (CRT) 的调试版本,例如 MSVCRTD.lib,而发布版本则链接到 MSVCRT.lib。 如果“使用调试库”设置为“否”,编译器将链接到发布 CRT,但代码和依赖项(如 TradeTools)可能仍需要调试符号和特定于调试的内存管理行为。
内存分配差异
调试和发布 CRT 管理内存的方式不同(例如,调试 CRT 添加填充并执行额外检查)。 如果 TradeTools 库使用调试设置进行编译,但与 Release CRT 链接,则任何跨界分配/释放(例如,DLL 中的新建、EXE 中的删除)都可能导致堆损坏或无效指针异常。
符号不匹配
调试版本通常包含用于调试的额外符号(如断言、额外的 std::vector 检查等)。 如果您正在运行调试版本但链接到发布 CRT,则可能会遇到“未找到入口点”或未解决的符号问题,因为链接的发布 CRT 中不存在调试符号。
感谢那些评论/帮助过的人。