в качестве ввода, чтобы он работал просто отлично. Время от времени удалитель может быть не идеальным.)

дал общий шаблон удаления, который можно использовать для созданияunique_ptr<>() подтипы, позволяющиеDeleter кроме простоdelete ptr.

Он прекрасно работает с флагами оптимизации по умолчанию (т.е.-O0), однако, когда я использую-O3 T & operator * () функция, так или иначе, возвращает0 вместоf_pointer содержание.

Я хотел бы убедиться, что мы согласны с тем, что в компиляторе что-то не так и мой шаблон верен. Ниже приведен полный фрагмент кода, который должен компилироваться в соответствии с Ubuntu 16.04 и Ubuntu 18.04 и, возможно, другими версиями, если они поддерживают C ++ 14 (см. Ниже для протестированных версий g ++).

// RAII Generic Deleter -- allow for any type of RAII deleter
//
// To break compile with:
//     g++ --std=c++14 -O3 -DNDEBUG ~/tmp/b.cpp -o b

#include <memory>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

template<class T, T null_value, class D, D deleter>
class raii_generic_deleter
{
public:
    class pointer
    {
    private:
        T f_pointer = null_value;

    public:
        pointer(T p)
            : f_pointer(p)
        {
        }

        pointer(std::nullptr_t = nullptr)
            : f_pointer(null_value)
        {
        }

        explicit operator bool () const
        {
            return f_pointer != null_value;
        }

        bool operator == (pointer const rhs) const
        {
            return f_pointer == rhs.f_pointer;
        }

        bool operator != (pointer const rhs) const
        {
            return f_pointer != rhs.f_pointer;
        }

        T & operator * ()
        {
            return f_pointer;
        }
    };

    void operator () (pointer p)
    {
        deleter(*p);
    }
};


typedef std::unique_ptr<int,
            raii_generic_deleter<int, -1, decltype(&::close), &::close>>
                        raii_fd_t;


int main(int argc, char * argv [])
{
    int fd = -1;

    {
        raii_fd_t safe_fd;

        std::cout << "default initialization: safe_fd = " << *safe_fd
                  << std::endl;

        fd = open("/tmp/abc.tmp", O_RDWR | O_CREAT, 0700);

        std::cout << "fd = " << fd << std::endl;

        safe_fd.reset(fd);

        std::cout << "safe_fd after the reset(" << fd
                  << ") = " << *safe_fd << std::endl;
    }

    if(fd != -1)
    {
        // assuming the safe_fd worked as expected, this call returns an error
        //
        int r = close(fd);
        int e(errno);

        std::cout << "second close returned " << r
                  << " (errno = " << e << ")" << std::endl;
    }

    return 0;
}

(Для оригинала см.raii_generic_deleter.h в веб-сайтах libsnap)

Есть вывод, который я получаю при использовании-O0 (без оптимизации):

default initialization: safe_fd = -1
fd = 3
safe_fd after the reset(3) = 3
second close returned -1 (errno = 9)

В этом случае*safe_fd возврат звонка-1 а также3 как и ожидалось. Это вызывает шаблонT & pointer::operator * () функция.

С любым уровнем оптимизации (-O1, -O2, -O3) вывод выглядит так:

default initialization: safe_fd = 0
fd = 3
safe_fd after the reset(3) = 0
second close returned -1 (errno = 9)

Как мы видим, дескриптор безопасного файла возвращает0 вместо-1 после инициализации, а затем снова0 когда это должно быть3, Однако деструктор правильно закрывает файл, так как второе закрытие завершается неудачно, как и ожидалось. Другими словами, как-то, описание файла (3) известен и правильно используется удалителем.

Когда я обновляю оператор указателя таким образом:

        T & operator * ()
        {
            std::cout << "f_pointer within operator * = " << f_pointer
                      << std::endl;
            return f_pointer;
        }

Тогда вывод с любым уровнем оптимизации будет правильным:

f_pointer within operator * = -1
default initialization: safe_fd = -1
fd = 3
f_pointer within operator * = 3
safe_fd after the reset(3) = 3
f_pointer within operator * = 3
second close returned -1 (errno = 9)

Вероятно, потому, что эта конкретная функция не оптимизирована полностью.

Составители:

Я тестировал со стоковым g ++ на Ubuntu 16.04

g ++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.9) 5.4.0 20160609

А также на Ubuntu 18.04

g ++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0

Я также пошел вперед и сообщил об этом какошибка на сайте GNU.

Ответы на вопрос(2)

Ваш ответ на вопрос