Inicializációs probléma c++

Inicializációs probléma c++
2017-12-12T18:55:23+01:00
2017-12-12T22:24:10+01:00
2022-10-15T21:30:23+02:00
natli
Sziasztok!

Nemrég váltottam Windows 10/Visual Studio 2015-re. Egy directx-es alkalmazást szeretnék írni, ahol egy láncolt listára vannak felfűzve a síkok (koordinátái, adatai....), de debug módban fordítva állandóan leáll az alábbi hibaüzenettel:

Exception thrown: read access violation._Ptr was 0xCDCDCDCD.

Dióhéjban a kód:

Game.h:

const int cMaxLabirintusSzelesseg = 199; const int cMaxLabirintusHosszusag = 199; struct SElem { ListaElem Koord; std::unique_ptr<DirectX::CommonStates> m_states; std::unique_ptr<DirectX::BasicEffect> m_effect; std::unique_ptr<DirectX::PrimitiveBatch<DirectX::VertexPositionColor>> m_batch; Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout; }; struct SikLancoltLista { int Sorszam; struct SElem Sik; struct SikLancoltLista *Kovetkezo; }; typedef bool tLabirintus[cMaxLabirintusHosszusag][cMaxLabirintusSzelesseg]; class Game { . . . private: struct SikLancoltLista *FelepitLancoltLista(tLabirintus); void FeltoltListaelem(struct SikLancoltLista *, const ListaElem, float, float); tLabirintus vLabirintus; SikLancoltLista *vSikLancoltLista; . . .

}

Game.cpp:

struct SikLancoltLista *Game::FelepitLancoltLista(tLabirintus lLabTomb) { struct SikLancoltLista *elso, *elozo, *aktualis; . . . aktualis = (struct SikLancoltLista *) malloc(sizeof(struct SikLancoltLista)); aktualis->Kovetkezo = NULL; aktualis->Sorszam = Sorszam; FeltoltListaelem(aktualis, KonstansSikSzembol, FutoPontX, FutoPontZ); if (Sorszam == 0) elso = elozo = aktualis; else { elozo->Kovetkezo = aktualis; elozo = aktualis; } Sorszam++; . . . } void Game::CreateDevice() { SikLancoltLista *aktualis; . . . aktualis = vSikLancoltLista; while (aktualis != NULL) { aktualis->Sik.m_states = std::make_unique<CommonStates>(m_d3dDevice.Get()); aktualis->Sik.m_effect = std::make_unique<BasicEffect>(m_d3dDevice.Get());; aktualis->Sik.m_effect->SetVertexColorEnabled(true); aktualis->Sik.m_effect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength); DX::ThrowIfFailed( m_d3dDevice->CreateInputLayout(VertexPositionColor::InputElements, VertexPositionColor::InputElementCount, shaderByteCode, byteCodeLength, aktualis->Sik.m_inputLayout.ReleaseAndGetAddressOf())); aktualis->Sik.m_batch = std::make_unique<PrimitiveBatch<VertexPositionColor>>(m_d3dContext.Get()); aktualis = aktualis->Kovetkezo; } . . . }


Azért akarok láncolt listát használni, mert a síkok száma futás időben dől el. De a CreateDevice eljárásnál a fentebb nevezett hiba állandóan fellép. Olyan az egész mintha a Sik struktúra m_states, m_effect, m_inputLayout és m_batch osztályai nem lennének inicializálva. Gyanítom a malloc nem elég az inicializáláshoz.
Visual Studio 2010-ben még a hasonló kódom működött, de amióta bevezették ezeket az új nyelvi elemeket, nem találok semmit.
Mutasd a teljes hozzászólást!
Szerintem **G** kolléga van jó nyomon ezzel a kérdésével:

Miért malloc és nem new?

Ugyan az std::unique_ptr-nek van default konstruktora, ami lényegében null pointerrel inicializálja, de a konstruktornak nincs esélye lefutni, mert malloc-ot használsz new helyett. A new operátor nyelvi elem, ezért a fordító tudni fogja, hogy az allokáció után neki le kell még futtatnia a konstruktorokat a megfelelő inicializáláshoz. A malloc csak egy mezei függvény, ami csak lefoglalja a memóriát, de nem inicializál semmit. Úgy is mondhatjuk, hogy te csak lefoglaltál sizeof(struct SikLancoltLista) bájt memóriát, nem pedig egy SikLancoltLista példányt hoztál létre a heapen. Nem meglepő, hogy a memóriaszemét nem úgy működik, mint ahogy egy példánytól elvárható.

A tanulság, hogy ha C++-os eszközöket használsz, akkor ne csak félig-meddig használd őket, hanem teljesen. (Vagy legalább is értsd meg, hogyan működnek.) Ha ennek megfelelően gondolkodsz, akkor nem is kezdtél volna saját láncolt listát írni, hanem használod mondjuk az std::vectort (vagy ha valamiért ragaszkodsz a láncolt listához, egy std::list-et).
Mutasd a teljes hozzászólást!

  • Ne csak debug kódot fordíts, hanem ténylegesen debugoljál is. Mivel tudod, hogy hol száll majd el, nem is kell Ádámtól-Évától kezdeni, tehetsz a környékre egy breakpointot. Persze a VS elvileg amúgy is megmutatná, hol hal meg, csak a C-C++ keverékkód esetleg bonyolítja az életet.

    Amúgy az itt közölt kódrészletekben a vSikLancoltLista nem kerül inicializálásra, és innentől kezdve az, hogy "aktualis=vSikLancoltLista" nem "bizonyít" semmit.
    Mutasd a teljes hozzászólást!
  • Miért így?

    SikLancoltLista *aktualis; .. aktualis = vSikLancoltLista;
    Nem átláthatóbb?

    SikLancoltLista *aktualis = vSikLancoltLista;
    C89-ben volt kötelező blokk elején deklarálni a válotózkat..
    C++-ban ne használj láncolt listát, ott vannak az STL containerek. (dinamikusak)
    Sokkal szebb, kompaktabb kódot tudsz írni a használatukkal és elkerülheted a kézzel pointeres láncolást, meg bohóckodást.

    0xCDCDCDCD
    "Uninitialized (global)"

    "Visual Studio 2010-ben még a hasonló kódom működött, de amióta bevezették ezeket az új nyelvi elemeket, nem találok semmit."
    Amiben nem vagy biztos azt vagy ne használd, vagy tanuld meg. STL containerek esetén tanácsosabb megtanulni..

    Miért malloc és nem new?

    Első ránézésre nem látom a hibát :(
    Mutasd a teljes hozzászólást!
  • Magic number (programming) - Wikipedia

    0xCDCDCDCD: Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory

    Initalizáld a változóid.
    Amúgy meg ocsmány a kódod, még az a részleg is amit belinkeltél. Kicsit formázhatnád jobban is.

    Meg ahogy már mondták is, C++ -ban ne foglalgass memóriát C eszközökkel, és tárolásra se te találd fel a kereket újra, hanem használj egy dinamikus tárolót, pl. egy dinamikus vektorba belerakhatod a pointereket az objectjeidre amiket new -al hoztál létre.
    Mutasd a teljes hozzászólást!
  • Szerintem **G** kolléga van jó nyomon ezzel a kérdésével:

    Miért malloc és nem new?

    Ugyan az std::unique_ptr-nek van default konstruktora, ami lényegében null pointerrel inicializálja, de a konstruktornak nincs esélye lefutni, mert malloc-ot használsz new helyett. A new operátor nyelvi elem, ezért a fordító tudni fogja, hogy az allokáció után neki le kell még futtatnia a konstruktorokat a megfelelő inicializáláshoz. A malloc csak egy mezei függvény, ami csak lefoglalja a memóriát, de nem inicializál semmit. Úgy is mondhatjuk, hogy te csak lefoglaltál sizeof(struct SikLancoltLista) bájt memóriát, nem pedig egy SikLancoltLista példányt hoztál létre a heapen. Nem meglepő, hogy a memóriaszemét nem úgy működik, mint ahogy egy példánytól elvárható.

    A tanulság, hogy ha C++-os eszközöket használsz, akkor ne csak félig-meddig használd őket, hanem teljesen. (Vagy legalább is értsd meg, hogyan működnek.) Ha ennek megfelelően gondolkodsz, akkor nem is kezdtél volna saját láncolt listát írni, hanem használod mondjuk az std::vectort (vagy ha valamiért ragaszkodsz a láncolt listához, egy std::list-et).
    Mutasd a teljes hozzászólást!
  • Hehe, ezt benéztem
    Látszólag inicializálja őket, csak mivel ezek smart pointerek, az előző értéküket megpróbálják felszabadítani, ami viszont nem-0.
    Igazából akartam is javasolni a calloc-ot, ha már pusztakezes harcművészkedés, csak láttam az inicializálást, ezért nem tettem.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd