Как заголовочный файл может безопасно включать стандартные библиотеки для потребителей, чтобы импортировать их - PullRequest
0 голосов
/ 18 января 2019

Предположим, я хочу создать следующий класс:

#pragma once
#include <memory>
#include <string>

namespace stackquestion
{
    struct Logger
    {
        void Log(std::string message);
    private:
        class Impl;
        std::unique_ptr<Impl> impl;
    };
}

Когда я хочу опубликовать класс, я заканчиваю в зависимости от определения моих потребителей std::string и std::unique_ptr. Я неясен в смысле публикации. Я подумываю о том, чтобы передать кому-нибудь библиотеку для статических или динамических ссылок.

Когда я возвращаюсь к версии без этих включений, я теряю комфорт / безопасность, которые я хотел получить.

#pragma once

namespace stackquestion
{
    struct Logger
    {
        void Log(const char *);
    private:
        class Impl * impl;
    };
}

Есть ли серебряная пуля, которую мне не хватает?

1 Ответ

0 голосов
/ 18 января 2019

Оба решения хороши, в зависимости от вашей цели.

Включая память и строку

Делая это, вы не нарушаете код, вы заставляете их использовать C ++ 11 или выше для использования вашей библиотеки. Тем не менее, я считаю это плюсом, так как вам не нужно возиться с множеством хитростей для поддержки C ++ 98.

При компиляции кода они не должны связываться со стандартной библиотекой, поэтому, если они делают что-то вроде #defined unique_ptr shared_ptr, я бы обвинял ваших пользователей в плохом кодировании, а не вас. И да, вы могли бы попытаться защитить от множества плохих вещей, сделанных пользователями, например, перегрузка operator& (адрес), однако вы в конечном итоге получили бы код, подобный реализациям STL, который тоже не очень хорош.

Использование pimpl

Использование прыща решает многие проблемы, упомянутые выше. Тем не менее, вы не должны использовать его из-за этого. Единственное реальное преимущество pimple - двоичная совместимость.

Поскольку вы не предоставляете STL или любые другие библиотеки, кроме своей собственной, вы не должны получать ошибки ссылок на std::string. (Да, это возможно)

Если вы компилируете свою библиотеку с помощью libc++, std::string на самом деле std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > с макетом памяти, специфичным для libcxx.

Если вы компилируете свою библиотеку с помощью libstdc++, std::string становится std::basic_string<char, std::char_traits<char>, std::allocator<char> > (или более длинным именем для варианта C ++ 11)

Подробнее см.

...