头文件如何安全地包含供使用者导入的标准库

时间:2019-01-18 16:29:48

标签: c++ header linker

假设我要创建以下类:

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

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

当我要发布类时,最终取决于我的消费者定义std::stringstd::unique_ptr。我对发布的含义含糊不清。我正在考虑将某人交给一个库进行静态或动态链接。

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

#pragma once

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

我缺少银弹吗?

1 个答案:

答案 0 :(得分:1)

两种解决方案都可以,这取决于您的目标。

包括内存和字符串

这样做,不会破坏代码,您确实迫使他们使用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变体的更长名称)

有关更多详细信息,请参见this thread