2014-10-01 12 views
5

Ho riscontrato una violazione di accesso quando si utilizza un QString in un elenco di inizializzazione che non capisco.QString nella lista di inizializzazione causa una violazione di accesso. Cosa va storto qui?

Ecco un esempio minimo che riproduce il problema.

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

struct Parameter 
{ 
    QString stringPar; 
}; 

class ClassA 
{ 
    QString m_string1; 

public: 
    void function(Parameter pars); 
}; 

Attuazione ClasseA ...

// 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 
} 

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

Lo stack di chiamate al momento della violazione:

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 

Qualcosa sembra sbagliare con l'assegnazione della copia i n ClassA :: function() ma non sono sicuro di cosa sia. Quando cambio la firma di funzione da

function(const Parameter& pars); 

che non va in crash neanche.

Avete qualche idea?

+2

non sembra che dovrebbe bloccarsi ... e non è precipitato su di me (Qt5.3, gcc4.8.2, kubuntu a 32 bit). Quale compilatore, versione di Qt, OS, ecc.? – HostileFork

+0

Windows 7 64 bit, Visual Studio 2013 con Update 2, Qt 5.1.1 – Knitschi

+1

Se si cambia 'QString' in' std :: string' funziona? – cmannett85

risposta

0

Si dovrebbe aggiungere un costruttore di copia:

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

Un esempio dei parametri di temperatura si crea quando si chiama ClasseA :: function() a causa di C++ passare gli argomenti per valore; Qualcosa di simile a questo:

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

Se non si scrive un costruttore di copia, compilatore sintetizzerà un costruttore di copia di default in questo modo:

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

immagino QString ha membri puntatore, assumendo il suo nome è ptr. quindi pars.stringPar.ptr e QString ("jkjsdghdkjhgdjufgskhdbfgskzh"). StringPar.ptr punterà allo stesso indirizzo di memoria.

funzione di chiamata in questo modo:

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

{QString ("jkjsdghdkjhgdjufgskhdbfgskzh")} oggetto distruggere prima di ritorno classA.function(), poi memoria puntata da {QString ("jkjsdghdkjhgdjufgskhdbfgskzh")} stringPar.. ptr viene liberato, e pars.stringPar.ptr puntano a memoria non valida.

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

Vedi < < Effective C++ >> Articolo 11: Dichiarare un costruttore di copia e un operatore di assegnazione per le classi con memoria allocata dinamicamente. Effective C++, 2E http://debian.fmi.uni-sofia.bg/~mrpaff/Effective%20C++/EC/EI11_FR.HTM

+0

QString ha un costruttore di copia e un operatore di allineamento. Ho menzionato nei commenti che il problema può essere riprodotto usando std :: string invece di QString. Quindi non vedo davvero perché avrei bisogno di scrivere il mio costruttore di copia per la struttura Parameter come quella di default dovrebbe essere ok. "{QString (" jkjsdghdkjhgdjufgskhdbfgskzh ")} l'oggetto distrugge prima di classA.function() return, ...". Ho pensato che le variabili senza nome negli argomenti delle funzioni sono garantite per vivere finché la funzione non ritorna, ma forse ho sbagliato. – Knitschi