Forum: PC-Programmierung Frage zu new/delete (C++)


von Sabi (herr_flitzpiep)


Lesenswert?

Hallo,

ich kann die Warnung beim Code unten (gegen Ende, bei "delete[] cells") 
nicht nachvollziehen. Der einzige Grund für eine fehlende 
Initialisierung von "cells" wäre doch eine Exception beim ersten new. 
Dann würde aber der Code im catch-Block gar nicht erreicht. Oder sehe 
ich das falsch?
1
int** alloc_cells(size_t rows, size_t columns)
2
{
3
  int** cells { new int* [rows] };
4
  
5
  size_t row_idx {};
6
  try {
7
    while (row_idx < rows) {
8
      cells[row_idx] = new int[columns];
9
      ++row_idx;
10
    }
11
  }
12
  catch (const std::bad_alloc&) {
13
    for (size_t remove_idx {}; remove_idx < row_idx; ++remove_idx) {
14
      delete[] cells[remove_idx];
15
    }
16
  
17
    delete[] cells; // Warning C6001: Using uninitialized memory 'cells'
18
    cells = nullptr;
19
20
    throw;
21
  }
22
23
  return cells;
24
}

Hinweis: Das ist eigentlich eine "Hilfs-Klassenfunktion" für eine kleine 
Übung aus einem Buch, bei der es um manuelles Speichermanagement geht; 
dass dies bei
"richtigem" C++-Code nicht so gemacht werden sollte, ist mir klar (und 
wird auch explizit erwähnt). Ich habe als Typ oben der Einfachheit 
halber statt "SpreadsheetCell" int verwendet.
1
// Vorgegeben
2
class Spreadsheet
3
{
4
  ...
5
  SpreadsheetCell** m_cells { nullptr };
6
};

von Oliver S. (oliverso)


Lesenswert?

Die Warnung liefert gerne mal false positives.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Vergiss die Warnung. Sie ist nicht nachvollziehbar, da cell ja definitiv
in Zeile 3 initialisiert wird. Das scheint eine blöde Eigenart des
MS-C++-Compilers zu sein, denn andere Compiler (g++ und clang++) liefern
keine Warnung.

von Rolf M. (rmagnus)


Lesenswert?

Yalu X. schrieb:
> denn andere Compiler (g++ und clang++) liefern keine Warnung.

Die warnen nur, wenn man die Initialisierung von cells entfernt. Da 
scheint also dieser Compiler einen Bug in der Kontrollfluss-Analyse zu 
haben.

von Oliver S. (oliverso)


Lesenswert?

„Die anderen“ sind bei der Warnung auch nicht ganz fehlerfrei. Das 
verhindern von false positives scheint nicht so trivial zu sein.

Oliver

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Oliver S. schrieb:
> „Die anderen“ sind bei der Warnung auch nicht ganz fehlerfrei. Das
> verhindern von false positives scheint nicht so trivial zu sein.

Ob eine Variable initialisiert ist oder nicht, ist nicht allgemein
entscheidbar. g++ und clang gehen mit diesem Problem auf verschiedene
Weise um:

g++ sagt "‘<variable>' may be used uninitialized", wenn er trotz
durchgeführter Kontrolflussanalyse sich nicht absolut sicher ist, dass
die Variable initialisiert ist. Das ist insbesondere dann der Fall, wenn
die Initialisierung der Variable fehlt und eine Zuweisung nur bedingt
erfolgt. Er verwendet das Wörtchen "may", um auf seine Unsicherheit
hinzuweisen.

clang++ sagt "'<variable>' is uninitialized when used here", wenn er
sich absolut sicher ist, dass die Variable uninitialisiert ist. Das ist
immer dann der Fall, wenn die Initialisierung der Variable fehlt und
keine Zuweisung (auch keine bedingte) vor der ersten Lesezugriff
erfolgt. Dadurch kann es allerdings passieren, dass bei einer
tatsächlich uninitialisierten Variable die Warnung ausbleibt.

Da er MS-Compiler mitunter auch dann warnt, wenn selbst ohne großartige
Kontrolflussanalyse offensichtlich ist, dass die Variable initialisiert
ist, wäre er gut beraten, seine Warnung "Using uninitialized memory
'<variable>' etwas weniger strikt (bspw. mit einem "Possibly" davor) zu
formulieren ;-)

von Sabi (herr_flitzpiep)


Lesenswert?

Danke für die Infos!
Wenn das bei einem "richtigen" Projekt auftritt, könnte man - wenn 
sicher ist, dass dort kein Problem vorhanden ist - vielleicht so etwas 
machen(?)
1
#if defined(_MSC_VER)
2
#define MSVC_DISABLE_WARNING_UNINITIALIZED_MEMORY __pragma(warning(push)) \
3
__pragma(warning(disable: 6001))
4
#define MSVC_RESTORE_WARNINGS __pragma(warning(pop))
5
#else
6
#define MSVC_DISABLE_WARNING_UNINITIALIZED_MEMORY
7
#define MSVC_RESTORE_WARNINGS
8
#endif
1
...
2
MSVC_DISABLE_WARNING_UNINITIALIZED_MEMORY
3
  ...
4
MSVC_RESTORE_WARNINGS

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Sabi schrieb:

> ich kann die Warnung beim Code unten (gegen Ende, bei "delete[] cells")
> nicht nachvollziehen.

cells hat einen definierten Wert, der Speicherbereich, auf den cells 
zeigt allerdings nicht. Die definierten Werte bekommt, cells erst in 
Zeile 8. Wenn in Zeile 8 eine Ausnahme auftritt, dann können noch einige 
Elemente von *cells nicht initialisiert sein. In der Ausnahmebehandlung 
wird dann delete auf nicht initialisierten Werten ausgeführt.

Ein Grund mehr, warum jedes Objekt maximal eine dynamische Resource 
verwalten sollte. Wenn Du cells durch einen std::vector ersetzt, ist das 
Problem schon gelöst.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Torsten R. schrieb:
> dann können noch einige
> Elemente von *cells nicht initialisiert sein. In der Ausnahmebehandlung
> wird dann delete auf nicht initialisierten Werten ausgeführt.

Nein, die for-Schleife durchläuft nur die zuvor korrekt angelegten 
Elemente.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Niklas G. schrieb:

> Nein, die for-Schleife durchläuft nur die zuvor korrekt angelegten
> Elemente.

Stimmt.

Beitrag #7487517 wurde vom Autor gelöscht.
Beitrag #7490104 wurde vom Autor gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.