首页 > 解决方案 > 头文件如何安全地包含标准库供消费者导入它们

问题描述

假设我要创建以下类:

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

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

当我想发布课程时,我最终取决于我的消费者对std::stringand的定义std::unique_ptr。我对发布的含义含糊不清。我正在考虑给某人一个用于静态或动态链接的库。

当我退回到没有这些内容的版本时,我最终会失去我想要获得的舒适/安全。

#pragma once

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

有没有我想念的灵丹妙药?

标签: c++headerlinker

解决方案


这两种解决方案都很好,具体取决于您的目标。

包括内存和字符串

这样做不会破坏代码,您会强制他们使用 C++11 或更高版本来使用您的库。但是,我认为这是一个加分点,因为您不必使用很多技巧来支持 C++98。

在编译代码时,他们不应该弄乱标准库,所以如果他们做了类似#defined unique_ptr shared_ptr我会责怪你的用户编码不好的事情,而不是你。是的,您可以尝试防止用户做很多坏事,例如重载operator&(地址),但是,您最终会得到像 STL 实现这样的代码,这也不是很漂亮。

使用 pimpl

使用 pimple 解决了上面提到的很多问题。但是,您不应该因此而使用它。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 变体的更长名称)

有关更多详细信息,请参阅此线程


推荐阅读