Pergunta

Eu tenho o seguinte código, e para a vida de mim, eu não consigo entender por que haveria uma exceção violação de acesso? Eu mesmo suprimido todas, TDS etc arquivos do OBJS e colocá-lo em um novo projeto, ainda a violação de acesso ocorre.

Essencialmente, este código exibe uma TListView em um TFrame e é mostrar os vários tempos atuais ao redor do mundo para diferentes fusos horários.

Nota:. O código está em C ++ Builder 6

alguém pode me ajudar?

BLOODY-HELL-update : Resolvido. Eu não deveria adicionar itens a TListView no construtor TFrame. MUDO MUDO MUDO.

Major Update : Parece que quando os UpdateTimes () é chamado através do temporizador, o "li-> Apagar" a propriedade é TRUE. Quando chamado fora do timer, ela é falsa. Agora, por que "li-> Apagar" ser definido como 'true', porque ele é chamado do timer? Se eu faço:

if(li->Deleting == false)
{
  li->Caption = "abcd";
}

Ela não entrar no if (), quando UpdateTimes () é chamado a partir do temporizador ...... argggggh !!!

UPDATE: Parece que se eu chamar UpdateTimes () fora do TTimer, ele funciona bem. Mas quando chamado a partir do timer, ele lança a violação de acesso. O que dá?

Arquivo de cabeçalho:

#ifndef CurrentTimes_FrameH
#define CurrentTimes_FrameH
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <ComCtrls.hpp>
#include <list>
using namespace std;
//---------------------------------------------------------------------------
struct LOCATIONTIMEINFORMATION
{
  AnsiString TimeZoneName;
  AnsiString PlaceName;
  int    UtcOffsetMinutes;
  TListItem* ListItem;
};
//---------------------------------------------------------------------------
class TCurrentTimesFrame : public TFrame
{
__published:    // IDE-managed Components
    TTimer *Timer;
    TListView *ListView;
    void __fastcall TimerTimer(TObject *Sender);
private:    // User declarations
public:     // User declarations
    __fastcall TCurrentTimesFrame(TComponent* Owner);
//---------------------------------------------------------------------------
//User Code
//---------------------------------------------------------------------------
private:
    list<LOCATIONTIMEINFORMATION>   FTimeInformation;
  typedef list<LOCATIONTIMEINFORMATION>::iterator LocationTimeInformationItr;
public:
  void AddTimeInformation(LOCATIONTIMEINFORMATION lti);
  void UpdateTimes();
};
//---------------------------------------------------------------------------
#endif

Arquivo CPP:

#include <vcl.h>
#pragma hdrstop
#include "CurrentTimes_Frame.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
__fastcall TCurrentTimesFrame::TCurrentTimesFrame(TComponent* Owner): TFrame(Owner)
{
  Timer->Enabled = false;
  <strike>{
    LOCATIONTIMEINFORMATION lti;
    lti.TimeZoneName = "UTC";
    lti.PlaceName = "Near Greenwich, England";
    lti.UtcOffsetMinutes = 0;
    AddTimeInformation(lti);
  }</strike>
  //UPADTED: Don't add TListItem from constructor 
}
//---------------------------------------------------------------------------
void TCurrentTimesFrame::AddTimeInformation(LOCATIONTIMEINFORMATION lti)
{
  TListItem* li = ListView->Items->Add();
  li->Caption = lti.TimeZoneName;
  li->SubItems->Add(lti.PlaceName);
  li->SubItems->Add(lti.UtcOffsetMinutes);
  li->SubItems->Add("<time will come here>");
  lti.ListItem = li;
  ShowMessage(AnsiString(lti.ListItem->ClassName())); //Correctly shows "TListItem"
  FTimeInformation.push_back(lti);

  {
  LOCATIONTIMEINFORMATION temp = FTimeInformation.front();
  ShowMessage(AnsiString(temp.ListItem->ClassName())); //Correctly shows "TListItem"
  }
  Timer->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TCurrentTimesFrame::TimerTimer(TObject *Sender)
{
    UpdateTimes();
}
//---------------------------------------------------------------------------
void TCurrentTimesFrame::UpdateTimes()
{
  Timer->Enabled = false;
  TListItem* li;
  for(LocationTimeInformationItr itr=FTimeInformation.begin();itr!=FTimeInformation.end();itr++)
  {
    li = itr->ListItem;

    ShowMessage(AnsiString(li->ClassName())); //Access Violation:
    /*
    ShowMessage() above shows:

    ---------------------------
    Debugger Exception Notification
    ---------------------------
    Project XX.exe raised exception class EAccessViolation with message 'Access violation at address 4000567D in module 'rtl60.bpl'. Read of address 00000000'. Process stopped. Use Step or Run to continue.
    ---------------------------
    OK   Help
    ---------------------------
    */
  }
  Timer->Enabled = true;
}
//---------------------------------------------------------------------------

Atualizar Um código de exemplo demo'ing essa lista leva itens como cópia, não de referência. (Tanto quanto eu posso ver, por favor me corrija se im fazendo algum erro no código abaixo)

@ Craig Young:

Estou confuso ... Achei estruturas seriam adicionadas à lista como um cópia não como uma referência? Por favor, dê uma olhada no código abaixo, parece que uma cópia está sendo feito? Ou estou faltando algo rudimentar? Ou um erro de codificação abaixo ??

void PopulateData()
{
    AnsiString DebugText;
    list<LOCATIONTIMEINFORMATION> Data;

  LOCATIONTIMEINFORMATION OnStack;

  //Prints "junk"
  DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);

    OnStack.TimeZoneName = "UTC";
    OnStack.PlaceName = "Near Greenwich, England";
    OnStack.UtcOffsetMinutes = 10;
    OnStack.ListItem = (TListItem*)20;

  //OnStack:
  DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
  //Add data to list
    Data.push_back(OnStack);

  //Get struct from list
  LOCATIONTIMEINFORMATION InList = Data.front();

  //OnStack:
  DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
  //InList:
  DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);

  //Change OnStack
    OnStack.TimeZoneName = "NONE";
    OnStack.PlaceName = "USA";
    OnStack.UtcOffsetMinutes = 50;
    OnStack.ListItem = (TListItem*)90;

  //OnStack:
  DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
  //InList:
  DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);

  //Change InList:
    InList.TimeZoneName = "SOME";
    InList.PlaceName = "BRAZIL";
    InList.UtcOffsetMinutes = 66;
    InList.ListItem = (TListItem*)88;

  //OnStack:
  DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
  //InList:
  DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);
}
Foi útil?

Solução

Editar : A minha resposta é incorreta, eu decidi deixá-lo no lugar porque é rolamento de valor em mente que, se a sua colecção (lista) contém elementos de referência, este é um muito real possibilidade de 'violações de acesso estranhas'. Os sintomas descritos se correlacionam perfeitamente se não tivesse sido para a lista STL manter uma cópia dos elementos.

Hi Liao,

Você escreveu: " BLOODY-HELL-update :.. Resolvido eu não deveria adicionar itens a TListView no construtor TFrame"

Eu vou discordar de você; você ainda não resolveu. Embora não seja necessariamente uma boa idéia (em termos de design), adicionando itens para TListView no construtor TFrame não deve causar violações de acesso.

Editar : Apesar da minha resposta abaixo sendo incorreto, eu ainda discordar de Liao '-HELL-update BLOODY'. Adição de itens para TListView no construtor TFrame não deve violações causa de acesso. Na verdade eu levei o código original e testado-lo em CPBB 2009, e ele funcionou perfeitamente. Isto sugere que o erro pode ter sido no modo como o quadro foi utilizado; ou algum outro aspecto do código que não foi demonstrada.

O problema é com a seguinte linha no construtor:

LOCATIONTIMEINFORMATION lti;
  • Este aloca lti na pilha.
  • Em seguida, adicione lti a uma lista; ou mais corretamente: você adicionar um referência em lti à lista .
  • Quando o construtor sai do escopo, o mesmo acontece lti; e que a memória pode ser reutilizado por qualquer outra parte do seu aplicativo.
  • Mais tarde, quando suas tentativas de temporizador a atualização, a referência no FTimeInformation ainda está lá.
  • Você usa esta referência para procurar onde lti foi .
  • Se essa seção da memória foi alterado por qualquer outra parte do seu aplicativo, em seguida, ltr->ListItem não faça mais referências a TListItem que foi criado no construtor. Em vez disso, faz referência a alguma outra parte da memória que ele tenta usar como se fosse um TListItem. Portanto, você experimentar problemas 'estranhos', tais como:
    • li-> Apagar == false
    • li-> ClassName causando uma violação de acesso.

NOTA: Se ou não você realmente obter uma violação de acesso geralmente depende um pouco da sorte: Considere-se sorte se do obter a violação de acesso; a outra opção é normalmente 'inexplicável' comportamento errático.

Tente modificar seu construtor da seguinte forma, deve corrigir a violação de acesso. NOTA: lti agora é alocada dinamicamente, você terá que decidir quando para libertá-la, caso contrário você terá um vazamento de memória;)

LOCATIONTIMEINFORMATION* lti = new LOCATIONTIMEINFORMATION;
lti->TimeZoneName = "UTC";
lti->PlaceName = "Near Greenwich, England";
lti->UtcOffsetMinutes = 0;
AddTimeInformation(*lti);

Outras dicas

Eu não posso realmente ver qualquer problema com o código.

Tente imprimir o TimeZoneName ou PlaceName do seu iterador, ao invés de li-> ClassName (), para fazer algo certo que você não adicionou acidentalmente mais para a lista ou algo assim ...

Que valores você tem em FTimeInformation? Por exemplo, é li == null?


Se podemos supor que a violação de acesso ocorre pela primeira vez através do laço, e Li aponta para uma TListItem válido, então talvez devêssemos dividir as três declarações sobre a linha ao longo de três linhas. Algo parecido com isto:

const char* className = li->ClassName();
AnsiString  ansiString(className);
ShowMessage(ansiString);

Se a violação de acesso não ocorre na primeira linha isso vai nos dizer alguma coisa interessante.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top