Teoretycznie powinienem móc używać niestandardowego typu wskaźnika i deletera, aby unikalny_ptr zarządzał obiektem, który nie jest wskaźnikiem. Próbowałem następujący kod:Używanie unique_ptr do kontrolowania deskryptora pliku
#ifndef UNIQUE_FD_H
#define UNIQUE_FD_H
#include <memory>
#include <unistd.h>
struct unique_fd_deleter {
typedef int pointer; // Internal type is a pointer
void operator()(int fd)
{
close(fd);
}
};
typedef std::unique_ptr<int, unique_fd_deleter> unique_fd;
#endif // UNIQUE_FD_H
to nie zadziała (GCC 4.7 z -std = C++ 11 parametrów). Reaguje z następujących błędów:
In file included from /usr/include/c++/4.7/memory:86:0,
from test.cc:6:
/usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = int; _Dp = unique_fd_deleter]':
test.cc:22:55: required from here
/usr/include/c++/4.7/bits/unique_ptr.h:172:2: error: invalid operands of types 'int' and 'std::nullptr_t' to binary 'operator!='
Od zagłębiając się w definicji unique_ptr, widzę dwa problemy, które uniemożliwiają go z pracy. Pierwszym, co wydaje się jawnym naruszeniem standardu, jest to, że destruktor dla unique_ptr porównuje "wskaźnik" (który jest, według mojej definicji, int) do nullptr, aby sprawdzić, czy jest on zainicjalizowany czy nie. Jest to sprzeczne ze sposobem, w jaki raportuje to poprzez konwersję boolowską, która polega na porównaniu go do "wskaźnika()" (niezainicjowanego "wskaźnika"). To jest przyczyną błędów, które widzę - liczba całkowita nie jest porównywalna z wartością nullptr.
Drugi problem polega na tym, że potrzebuję jakiegoś sposobu, by powiedzieć unique_ptr, czym jest niezainicjowana wartość. Chcę następujący fragment kodu do pracy:
unique_fd fd(open(something...));
if(!fd)
throw errno_exception("Open failed");
za to do pracy, unique_ptr musi wiedzieć, że „wartość niezainicjowany” jest -1, jak ważna jest zerowy deskryptor pliku.
Czy to błąd w gcc, czy staram się coś tutaj zrobić, czego po prostu nie da się zrobić?
Dzięki Shachar
dodam oczywiste. Zamiast "int" mogę ustawić typ wskaźnika na jakąś klasę, którą wymyślam. Pozwoli mi to zrobić wszystko, co chcę. Nie będzie to jednak banalna klasa, ponieważ wymaga niejawnych rzutów do int i innych rzeczy, których wolałbym uniknąć. –
Proponuję zaprzestać używania 'std :: unique_ptr' dla przechowywania non-pointer. Oczekuje, że dane rzeczywiście będą wskaźnikiem, a Ty chcesz, aby był _niespokoleniowym_. –
Zawiń API pliku wewnątrz innej klasy (RAII), która otwiera plik i przechowuje deskryptor pliku. Klasa powinna zamknąć deskryptor po wywołaniu destruktora. Następnie użyj unikalnego wskaźnika takiej klasy. –