初始化列表中的QString导致访问冲突。这里出了什么问题?

时间:2014-10-01 20:04:44

标签: c++ qt visual-c++ access-violation initializer-list

我在初始化列表中使用QString时遇到了访问冲突,我不明白。

这是一个重现问题的最小例子。

// file ClassA.h
#pragma once
#include <QString>

struct Parameter
{
    QString stringPar;
};

class ClassA
{
     QString m_string1;

public:
    void function(Parameter pars);
};

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
}

和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;
}

违规时的调用堆栈:

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

ClassA :: function()中的复制赋值似乎出了问题,但我不确定它是什么。 当我将功能的签名更改为

function(const Parameter& pars);

它也不会崩溃。

你有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您应该添加一个复制构造函数:

struct Parameter
{
    QString stringPar;
    Parameter& Parameter(const Parameter& rhs)
    {
        if((void*)this == (void*)&rhs)
        {
            return *this;
        }
        this->stringPar = rhs.stringPar;
        return *this;
    }
};

当您调用ClassA :: function()时,会创建一个临时参数实例,因为C ++按值传递参数; 像这样:

void ClassA::function(Parameter pars = QString("jkjsdghdkjhgdjufgskhdbfgskzh"))
{
    m_string1 = pars.stringPar;   // last line called in my code when the crash happens
}

如果您不编写复制构造函数,编译器将合成一个默认的复制构造函数,如下所示:

    Parameter& Parameter(const Parameter& rhs)
    {
        memcpy(this, &rhs, sizeof(Parameter));
        return *this;
    }

我猜QString有指针成员,假设它的名字是ptr。 然后是pars.stringPar.ptr和QString(“jkjsdghdkjhgdjufgskhdbfgskzh”)。stringPar.ptr将指向相同的内存地址。

这样调用函数:

 classA.function({ QString("jkjsdghdkjhgdjufgskhdbfgskzh") });

{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.

参见&lt;&lt;有效的C ++&gt;&gt; 第11项:为具有动态分配内存的类声明复制构造函数和赋值运算符。 有效的C ++,2E http://debian.fmi.uni-sofia.bg/~mrpaff/Effective%20C++/EC/EI11_FR.HTM