Запретить клиентам сохранять указатели, возвращаемые классом C ++ - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть класс file_manager, который отслеживает файлы в данном каталоге.Я использую его как модель для файлового интерфейса, похожего на Windows Explorer или macOS Finder.file_manager имеет различные методы find(), позволяющие клиентам запрашивать дескрипторы файлов, и эти методы возвращают optional, который будет пустым, если ни один файл не соответствует этому критерию поиска.

Поскольку файлы могут бытьВ любое время, без нашего ведома, вы можете удалить из каталога комментарий о методах find(), в котором говорится, что вы не должны сохранять указатели, которые они вам дают.Вместо этого вам следует просто запросить file_manager позже (например, один раз за кадр / один раз за обновление пользовательского интерфейса / и т. Д.).Это правило помогает избежать необходимости оборачивать каждое будущее использование file_handle чем-то вроде is_still_on_disk() проверки.

Вот как выглядит код в настоящее время:

struct file_handle {
    std::string path;
    std::string contents;
    // Other metadata here
};

class file_manager {
public:
    file_manager(std::string directory_to_manage);

    // Clients shouldn't retain this pointer, because the file could
    // disappear from disk at any time.
    // Empty if we were unable to find a file with this name.
    optional<const file_handle *> find_file_by_name(std::string file_name) const;
    optional<const file_handle *> find_file_modified_before(time_t time) const;
    // other find_xxx() methods here

    // Examines the disk to add/remove from all_known_files to match the
    // current state of the directory.
    // Only called at well-defined times, from the same thread that uses
    // the "find" methods.
    void update();

private:
    std::list<file_handle> all_known_files;
}

Есть лиспособ кодифицировать это правило "не сохранять" таким образом, чтобы вы получили ошибку компиляции (или ее ошибку, ошибку подтверждения времени выполнения), если бы вы сохранили возвращаемое значение метода "find" как переменную-член?(Если это возможно, было бы неплохо предотвратить его превращение в статическую переменную.)

То есть я бы хотел иметь возможность вместо методов file_manager::find_xxx() возвращать необязательную "не сохраняемую" оболочку... что-то вроде этого:

class file_manager {
    . . .
    optional<cant_retain_me<file_handle>> find_file_by_name(std::string file_name) const;
    . . .
}

... где оболочка cant_retain_me позволит этому коду работать:

void do_stuff() {
    auto optional_file = my_file_manager.find_file_by_name("foo.txt");
    if(optional_file.has_value()) {
         cant_retain_me<file_handle> handle = *optional_file;
         // use handle as though it were a normal file_handle or file_handle *
    }
}

... но нарушит этот код:

class client {
    client() {
        auto optional_file = my_file_manager.find_file_by_name("foo.txt");
        if(optional_file.has_value()) {
            my_handle = *optional_file;
        } else { /* use some fallback value */ }
    }

    void do_stuff() {
        // Try to use my_handle as though it were a normal file_handle or file_handle *
    }

    cant_retain_me<file_handle> my_handle;
}

Две идеи, которые я рассмотрел для оболочки:

  • Предотвращение создания экземпляра класса оболочки в куче.Это немного поможет (это лучше, чем ничего!), Но не мешает использованию, показанному в client выше.
  • Сделайте класс оболочки только для перемещения (delete конструктор копирования).Я думаю это сработало бы, так как это по крайней мере заставило бы клиентов писать какой-то очень неуклюжий код для хранения дескриптора как члена ... но я не пишу много кода с явными перемещениями, поэтому яЯ не совсем уверен, будет ли это иметь желаемый эффект.

Я понимаю, что на языке с memcpy() никогда не будет способа полностью запретить клиентам плохое поведение, но я быЯ хотел бы, чтобы он неправильно использовал API, насколько это возможно, пахло кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...