代码之家  ›  专栏  ›  技术社区  ›  Johannes

头文件如何安全地包含标准库以供用户导入?

  •  0
  • Johannes  · 技术社区  · 6 年前

    假设我要创建以下类:

    #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 回复  |  直到 6 年前
        1
  •  1
  •   JVApen    6 年前

    这两种解决方案都很好,这取决于你的目标是什么。

    包括内存和字符串

    这样做,不破坏代码,你确实强迫他们有C++ 11或以上使用你的库。但是,我认为这是一个优点,因为你不必为了支持C++ 98而浪费很多技巧。

    在编译代码时,它们不应该与标准库混淆,因此如果它们执行类似的操作 #defined unique_ptr shared_ptr 我会责怪你的用户编码不好,而不是你。是的,你可以试着避免用户做了很多不好的事情,比如过载。 operator& (地址),但是,您最终会得到类似STL实现的代码,这也不是很好。

    使用PIMPL

    使用粉刺可以解决上面提到的许多问题。但是,你不应该因为这个而使用它。丘疹的唯一真正优点是二进制兼容性。

    由于您不公开STL或任何其他库(除了您自己的库),因此不应在上获取链接错误 std::string . (是的,这是可能的)

    如果用 libc++ , STD::字符串 实际上是 std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > 具有特定于libcxx的内存布局。

    如果用 libstdc++ , STD::字符串 变成 std::basic_string<char, std::char_traits<char>, std::allocator<char> > (或者C++ 11变体的更名)

    this thread 有关详细信息