Kni*_*chi 6 c++ qt access-violation initializer-list visual-c++
我在初始化列表中使用QString时遇到了访问冲突,我不明白.
这是一个重现问题的最小例子.
// file ClassA.h
#pragma once
#include <QString>
struct Parameter
{
QString stringPar;
};
class ClassA
{
QString m_string1;
public:
void function(Parameter pars);
};
Run Code Online (Sandbox Code Playgroud)
ClassA的实施......
// file ClassA.cpp
#include "ClassA.h"
void ClassA::function(Parameter pars)
{
m_string1 = pars.stringPar; // last line called in my code when the crash happens
}
Run Code Online (Sandbox Code Playgroud)
和main.cpp
// file main.cpp
#include "ClassA.h"
int main()
{
ClassA classA;
classA.function({ QString("jkjsdghdkjhgdjufgskhdbfgskzh") });
// when using this code the problem does not occur
//Parameter par = { QString("jkjsdghdkjhgdjufgskhdbfgskzh") };
//classA.function(par);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
违规时的调用堆栈:
Qt5Cored.dll!QGenericAtomicOps<QAtomicOpsBySize<4> >::load<long>(const long & _q_value) Line 96
Qt5Cored.dll!QBasicAtomicInteger<int>::load() Line 142
Qt5Cored.dll!QtPrivate::RefCount::ref() Line 57
Qt5Cored.dll!QString::operator=(const QString & other) Line 1355
EducationalCode.exe!ClassA::function(Parameter pars) Line 6
EducationalCode.exe!main() Line 8
Run Code Online (Sandbox Code Playgroud)
ClassA :: function()中的复制赋值似乎出了问题,但我不确定它是什么.当我将函数的签名更改为
function(const Parameter& pars);
Run Code Online (Sandbox Code Playgroud)
它也不会崩溃.
你有什么主意吗?
您应该添加一个复制构造函数:
struct Parameter
{
QString stringPar;
Parameter& Parameter(const Parameter& rhs)
{
if((void*)this == (void*)&rhs)
{
return *this;
}
this->stringPar = rhs.stringPar;
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
当您调用 ClassA::function() 时,会创建一个临时参数实例,因为 C++ 按值传递参数;像这样的东西:
void ClassA::function(Parameter pars = QString("jkjsdghdkjhgdjufgskhdbfgskzh"))
{
m_string1 = pars.stringPar; // last line called in my code when the crash happens
}
Run Code Online (Sandbox Code Playgroud)
如果你不编写复制构造函数,编译器将合成一个默认的复制构造函数,如下所示:
Parameter& Parameter(const Parameter& rhs)
{
memcpy(this, &rhs, sizeof(Parameter));
return *this;
}
Run Code Online (Sandbox Code Playgroud)
我猜 QString 有指针成员,假设它的名称是 ptr。那么 pars.stringPar.ptr 和 QString("jkjsdghdkjhgdjufgskhdbfgskzh").stringPar.ptr 将指向相同的内存地址。
调用函数如下:
classA.function({ QString("jkjsdghdkjhgdjufgskhdbfgskzh") });
Run Code Online (Sandbox Code Playgroud)
{ QString("jkjsdghdkjhgdjufgskhdbfgskzh") } 在 classA.function() 返回之前销毁对象,然后 {QString("jkjsdghdkjhgdjufgskhdbfgskzh")}.stringPar.ptr 指向的内存被释放,并且 pars.stringPar.ptr 指向无效内存。
// when using this code the problem does not occur
//Parameter par1 = { QString("jkjsdghdkjhgdjufgskhdbfgskzh") };
//classA.function(par1)
//par1 destroy when main() function return, thus classA.function() does not crash.
Run Code Online (Sandbox Code Playgroud)
请参阅《Effective C++》第 11 条:为具有动态分配内存的类声明复制构造函数和赋值运算符。有效的 C++,2E http://debian.fmi.uni-sofia.bg/~mrpaff/Effective%20C++/EC/EI11_FR.HTM