Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

07.03.2015, 17:13

Memorymanagement C++

Hallo Leute,
Programmiere gerade eine Entity Component System basierte Engine. Die Components in einem GameObject speichere ich in einem unique_ptr vector:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// header
class GameObject
{
      void addCompoenent(GameComponent *component);
      std::vector<std::unique_ptr<GameComponent>> _components;
};

// cpp
void GameObject::addComponent(GameComponent *component)
{
     _components.push_back(std::unique_ptr<GameComponent>(std::move(component));
}

// aufruf

addComponent(new PhysicsComponent());   // entstehen dadurch Speicherlecks?

// bzw.
PhysicsComponent* p = new PhysicsComponent();
addComponent(p);

Ist dies korrekt? oder entstehen Speicherlecks?

Danke

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »DerUltraLord« (07.03.2015, 17:24)


2

07.03.2015, 18:19

Speicherlecks entstehen so noch nicht direkt, aber man will es trotzdem eigentlich anders machen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// header
class GameObject
{
      void addCompoenent(std::unique_ptr<GameComponent> component);
      std::vector<std::unique_ptr<GameComponent>> _components;
};

// cpp
void GameObject::addComponent(std::unique_ptr<GameComponent> component)
{
     _components.emplace_back(component);
}

// aufruf

addComponent(make_unique<PhysicsComponent>());

// bzw.
auto  p = make_unique<PhysicsComponent>();
addComponent(std::move(p));


Du willst, dass Objekte über ihre gesamte Laufzeit von unique_ptr'n besessen werden, denn so ist garantiert, dass Speicherlecks unmöglich sind (außer man legt es drauf an). Deshalb kannst du komplett auf 'new' verzichten und einfach immer make_unique<>() benutzen. Durch das 'auto' sparst du dir den Typen zweimal zu schreiben, somit ist es nicht unübersichtlicher als mit dem new. Und da alles nur noch in unique_ptr'n ist, musst du 'move' benutzen, um den Besitz zu übertragen. Das 'emplace_back' soll in diesem Fall ein implizites move durchführen, ansonsten geht natürlich auch ein push_back(move(component)).
Aber ansonsten: Schön gedacht und an der richtigen Stelle nachgefragt, mit den paar Anmerkungen bist du jetzt sicherlich auf einem sehr guten Weg.
Lieber dumm fragen, als dumm bleiben!

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

3

07.03.2015, 18:24

Aber mit ECS hat das wenig zu tun.

4

07.03.2015, 18:27

make_unique


Aber erst ab C++14, TE hat nicht erwähnt welche IDE er nutzt.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

5

07.03.2015, 18:28

Nein, das nicht. Wirft der Konstruktor von PhysicsComponent eine Exception, so hat die Lebenszeit des Objekts noch nicht begonnen (Kein Destruktor-Aufruf). new wird daraufhin automatisch delete aufrufen. Sollte new eine Exception werfen, kommt es garnicht erst zum Aufruf des Konstruktors der PhysicsComponent.

Allerdings hat dein Code eine andere Bug-Quelle:
Stell dir mal folgenden Code eines Nutzers vor, der RTFM nicht eingehalten hat.

C-/C++-Quelltext

1
2
3
4
{ // new scope
  PhysicsComponent _pc{};
  _my_game_object->addComponent(&_pc);
} // _pc dies here.

C-/C++-Quelltext

1
2
3
4
GameComponent* _gc = new PhysicsComponent{};
_my_game_object->addComponent(&_gc);
do_dem_stuffz();
delete _gc;

Du lässt es zu, dass deine Funktion Raw Pointer annimmt. Das gibt dem Nutzer keine Auskunft darüber, wer sich jetzt ums Aufräumen kümmern soll. Besser wäre es wohl, die Komponenten per unique_ptr zu überreichen. Und nicht per unique_ptr-Referenz. Dadurch ist klar, dass ab jetzt GameObject die Verantwortung inne hat, das Zeug zu löschen. Das sähe dann so aus:

C-/C++-Quelltext

1
2
3
4
// Falls ich mich grad nicht irgendwo vertan haben sollte...
void GameObject::addComponent(std::unique_ptr<GameComponent>&& _c) {
  _components.emplace_back(std::move(_c));
}

C-/C++-Quelltext

1
_my_game_object->addComponent(std::make_unique<PhysicsComponent>());



Edit: Wie schnell hier alle tippen. D:

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

6

08.03.2015, 09:31

Guten Morgen und Danke für eure Antworten :),

Ich werde versuchen make_unique von c++ 14 zu benutzen und mein Funktionssignaturen anpassen.
Noch eine kleine Frage....
Ich sehe im TaskManager von Windows dass mein Prozess bei der Erstellung von Objekten bzw. Componenten mehr Arbeitsspeicher verbraucht.
Leider wird er bei der Zerstörung der Objekte nicht wieder vom Betriebssystem zurückgenommen.
Ich hab schon recherchiert und gelesen, dass das Betriebssystem den Speicher trotzdem für den Prozess in Anspruch nimmt.
Stimmt das?

Muss ich mir Sorgen machen? :D

7

08.03.2015, 09:44

Du bekommst einen relativ großen Bereich an Speicher (vermutlich 1 KB bis einige MB, das hängt vom Betriebssystem ab), der meistens größer als dein Objekt ist. Den behältst du, solange du mindestens ein Objekt in diesem Bereich gespeichert hast. Wenn du 1000 Objekte erzeugst und wieder löscht, dann sollte dein Prozess genauso viel Speicher wie zuvor verbrauchen.
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

8

08.03.2015, 09:48

Kurze Antwort: Hör nicht auf den Taskmanager:

http://zfx.info/viewtopic.php?f=4&t=3644…kmanager#p45896
Lieber dumm fragen, als dumm bleiben!

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

9

08.03.2015, 10:27

Es gibt wohl diese kleine Funktion um ungenutzten Speicher wieder an das OS zurückzugeben: https://msdn.microsoft.com/en-us/library…=vs.120%29.aspx
Was ist der Sinn in deinem Fall diese Funktion aufzurufen: Keiner. Die ist wirklich nur was für Spezialfälle.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

10

08.03.2015, 12:15

Hallo Leute,
Programmiere gerade eine Entity Component System basierte Engine. (...) Ist dies korrekt?
Technisch ist vieles möglich, aber einen großen Vorteil eines ECS machst Du damit komplett kaputt. Wenn Du Dir mehr Performance als ein normales OOP-Design erhoffst, muss ich Dich schon jetzt enttäuschen. Mit diesem Ansatz wird da nichts performanter.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige