2009-02-05 12 views
10

Ich habe eine Linux C++ - Anwendung und ich möchte einen Objektzeiger auf Gültigkeit testen, bevor es Dereferenzierung. Try/catch funktioniert jedoch unter Linux wegen des Segmentierungsfehlers nicht. Wie kann das gemacht werden?Try/Fang einen Segmentierungsfehler unter Linux

Antwort

8

Wenn Sie ein Szenario haben, in dem viele Zeiger in Ihrer App auf dieselben Objekte mit begrenzter Lebensdauer verweisen, ist eine gängige Lösung die Verwendung von boost smart pointers. Edit: in C++ 11, sind diese beiden Typen in der Standardbibliothek verfügbar

Sie würden wollen shared_ptr für Zeiger verwenden (s), die für die Lebensdauer des Objekts und weak_ptr für die anderen Zeiger verantwortlich sind , die ungültig werden können. Sie werden sehen, dass weak_ptr die Gültigkeitsprüfung hat, nach der Sie gefragt haben.

+0

Ich habe shared_prt nicht verwendet, aber soweit ich verstehe, ist es ein Zeiger, der Ich habe eine entgegengesetzte Situation, ich habe ein Objekt, das sich selbst löschen kann, wenn ich eine Nachricht erhalte, und ich brauche die, die darauf zeigen, dass ich eine Möglichkeit habe, zu wissen, dass sie etwas besitzen s ungültiger Zeiger. – jackhab

+1

Das ist genau die Art von Fall, für die weak_ptr gemacht wird. Der weak_ptr lässt das Objekt sterben und meldet Ungültigkeit, wenn Sie später versuchen, über das weak_ptr auf das Objekt zuzugreifen. Eine viel bessere Lösung als SIGSEGV zu fangen! – timday

+0

Das dachte ich, Ihre Situation war. Die Nachricht "delete me" sollte den one-and-only shared_ptr zurücksetzen. Danach wissen alle weak_ptrs, die von diesem shared_ptr stammen, dass sie ungültig sind. Werfen Sie einen Blick auf den Link "weak_ptr" für Beispiele. –

4

Initialisieren Sie den Zeiger auf NULL. Wenn es nach einer Verarbeitung immer noch NULL ist, ist es ungültig, ansonsten ist es gültig.

+0

Wenn ich ein Objekt löschen, es ist Zeiger ist nicht NULL, zeigt aber auf ungültigen Speicher. Wie kann ich einen solchen Zeiger validieren? – jackhab

+1

Warum zum Teufel würdest du überhaupt wollen? Du hast es gelöscht. Wenn Sie irgendwo Zeiger verwenden und nicht sicher sind, ob sie gelöscht sind oder nicht, tun Sie etwas sehr falsch. – Bombe

+0

Ich zweite das. Ungültige Zeiger sind ungültige Zeiger. Entweder danach ist die Zeigervariable nicht mehr zugänglich oder Sie setzen sie auf 0. Oder, da dies C++ ist, erfahren Sie mehr über RAII. – gimpf

4

Sie könnten einen Signalhandler für SIGSEGV für dieses eine Ereignis aktivieren. Details finden Sie auf der Manpage "signal". Die andere Alternative besteht darin, Referenzen zu verwenden, die garantiert gültig sind. Es hängt natürlich von Ihrer Anwendung ab.

+0

Die Manpage besagt, dass der Prozessstatus nicht definiert ist, wenn er SIGSEGV ignoriert. Kann ich nach dem Abfangen von SIGSEGV die C++ - Anwendung fortsetzen? – jackhab

+0

Gute Frage - wahrscheinlich nicht sicher. Ich denke, es ist im Allgemeinen besser, Referenzen anstelle von Zeigern zu verwenden, wenn Sie um die Gültigkeit besorgt sind. Wie die anderen Poster aufgezeigt haben, können Sie protokollieren, wo der Fehler auftritt, und ihn korrigieren. –

+0

Referenzen sind ebenfalls nicht garantiert gültig. Wenn die Lebensdauer des referenzierten Objekts endet, bevor die Referenz verwendet wird, sind die Ergebnisse ebenfalls undefiniert (in der Praxis identisch mit einem ungültigen Zeiger). Referenzen können nicht auf null initialisiert und nicht zurückgesetzt werden. Das ist es. – gimpf

8

Ein Segmentierungsfehler ist keine Ausnahme (wie Java NullPointerException); Es ist ein Signal, das vom Betriebssystem an den Prozess gesendet wird. Werfen Sie einen Blick auf the manpage for sigaction für Hinweise zur Installation eines Handlers für den Segmentierungsfehler (SIGSEGV).

1

Wie testen Sie den Zeiger auf Gültigkeit? Mit NULL vergleichen?

Am besten führen Sie Ihr Programm unter Valgrind. Ein Fehler könnte an einem ganz anderen Ort sein.

Update: Auf der Win32-Plattform gibt es etwas wie __try __except, das einige Ausnahmen abfangen kann. Soweit ich weiß, gibt es kein Linux-Äquivalent für diese Win32-Funktion.

+0

Unter Windows können Sie eine Ausnahme beim Zugriff auf einen Zeiger auf deallocated Objekt abfangen und Sie können mit der Situation umgehen. Unter Linux erhalten Sie SIGSEGV. Meine Frage gibt es eine Möglichkeit, eine zu validieren Zeiger, der einmal auf ein Objekt zeigte und daher nicht NULL ist, aber durch den Löschoperator ungültig gemacht wird – jackhab

+0

Ich bin kein Win32-Experte, aber ich benutzte __try __except für solche Dinge. –

+0

Das sind nur Windows-Sachen, die die Plattform "Structured exception handling "(SEH) in C++. Das Linux-Äquivalent ist Signale ... aber ich denke, Shmoopty's Vorschlag von shared_ptr/weak_ptr ist mehr auf der richtigen Linie. – timday

0

Wenn Sie einen Handler an die SIGSEGV anhängen, können Sie nicht viel mehr tun, als die Tatsache zu protokollieren, dass der Fehler aufgetreten ist und ordnungsgemäß fehlschlägt. Ihr Programm befindet sich in einem undefinierten Zustand, wenn dieser Verstoß auftritt, und daher ist es möglicherweise nicht sicher, den normalen Betrieb fortzusetzen.

Jenseits der Überprüfung auf NULL Ich glaube nicht, dass es eine Möglichkeit gibt zu überprüfen, ob ein Zeiger in dem von Ihnen beschriebenen Sinn "gültig" ist. Während des normalen Betriebs sollten Fehler wie diese nicht auftreten, da sie einen Fehler darstellen. Daher sollten Sie Ihr Programm, wenn auch in gutem Zustand, fehlschlagen lassen sollten.

0

Zeiger werden in Objekten gespeichert. Sie werden im Konstruktor möglicherweise auf 0 (NULL) initialisiert. Sie werden im Destruktor gelöscht, möglicherweise in der Zuweisung und selten in anderen Funktionen. Wenn sie in anderen Elementen als dem Destruktor gelöscht werden, wird ihnen sofort ein neuer Wert oder 0 zugewiesen.

2

Es gibt keine natürliche, universelle Methode mit rohen C++ - Zeigern. C++ geht davon aus, dass Sie diese Informationen verfolgen werden.

In den meisten Situationen können Sie damit umgehen, indem Sie daran denken, Zeiger auf NULL zu setzen, wenn sie ungültig sind. Neue Zeiger, die anfangs nicht zeigen, sollten auf NULL gesetzt werden und neu gelöschte Objekte sollten ihre Zeiger auf NULL setzen.