标签: pimpl-idiom

我应该到处使用 PIMPL 吗?

我当前的项目涉及编写 C++ API,我决定使用 PIMPL 惯用语。

我应该在我的项目中的任何地方使用 PIMPL idiom,例如我需要创建一个继承自 的自定义类,std::exception我应该用 PIMPL idiom 设计这个类还是我可以只写一个公共实现?

仅仅因为我使用 PIMPL 习惯用法就认为我创建的每个类都应该围绕它设计,这感觉是错误的。是否有应该在哪里PIMPL任何异常,没有用?

c++ idioms pimpl-idiom

5
推荐指数
1
解决办法
961
查看次数

包含一个以 std::unique_ptr<T> 作为字段的类,而“T”是不完整类型

std::unique<B>我为incomplete type创建了一个小测试用例B

测试.h

#pragma once
#include <memory>
class B;   //<--- compile error here
class Test{
    std::unique_ptr<B> bPtr;   
    //#1 need to move destructor's implementation to .cpp
    public: ~Test();
};
Run Code Online (Sandbox Code Playgroud)

测试.cpp

#include "Test.h"
class B{};
Test::~Test(){}  //move here because it need complete type of B
Run Code Online (Sandbox Code Playgroud)

主程序

#include <iostream>
#include "Test.h"
using namespace std;
int main(){
   Test test;
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误:-

/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22:错误:“sizeof”对不完整类型“B”的无效应用

据我了解,编译器告诉我这 B是一个不完整的类型(in main.cpp),因此它无法B正确删除。

但是,在我的设计中,我不想main.cpp拥有完整B.
粗略地说,这是一个粉刺。

有没有好的解决方法?

这里有一些类似的问题,但没有一个提出干净的解决方法。 …

c++ pimpl-idiom unique-ptr incomplete-type c++11

5
推荐指数
0
解决办法
184
查看次数

使用可变参数模板函数围绕类实现基于 pImpl 的包装器

概括

我正在编写一个库和一个客户端应用程序。在库中,我正在尝试围绕另一个静态链接的第三方库(特别是spdlog)编写一个包装器,并尝试使用 pImpl 习惯用法将它完全隐藏在客户端应用程序之外。问题是第三方库使用了可变参数模板函数,所以我也需要在我的库中使用。

背景

我对包装器的第一次尝试非常简单和直接,但后来我在我的客户端应用程序中收到“没有这样的文件或目录”错误,因为第三方标头包含在我的库标头中。

我接下来尝试创建一个 pImpl 类并编译它,但在客户端我再次收到“未定义引用”链接器错误。

将实现的源代码拉到我的包装器的标题中,让我回到最初的“没有这样的文件”问题。对此进行研究后,我开始认为不可能围绕可变参数模板制作包装器,但我不确定。这是我第一次尝试制作可变参数函数/模板。

示例代码

这是我的项目目前的情况:

为了简洁和清晰,几乎所有的命名空间、函数名称、标题等都已被编辑(或删除)。

客户端应用程序 - sandbox.cpp

#include "sandbox.h"
#include <logger.h>  //  <-- This is all I want clients to see.

int Sandbox::run() {
    LOG_INFO("Hello World!");        // My library is providing this.
    LOG_INFO("Hello {}", "indeed!"); // And, this variable input function.
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的图书馆 - logger.h

class LoggerImp;  // Forward declaration of implementation.

class LIB_EXPORT Logger {
  public:

    /* Constructors, destructor, etc. */

    template <typename... Args>
    void info(const …
Run Code Online (Sandbox Code Playgroud)

c++ templates pimpl-idiom wrapper variadic-templates

5
推荐指数
1
解决办法
916
查看次数

C++ pimpl 习语:在 API 类的 getter 中返回 impl 指针

我对我的库的公共 API 中的类使用 pimpl 习惯用法,以受益于它的 ABI 稳定性等属性。在我的非公开代码中,访问 impl 对象并直接对其进行操作会很方便。

向 API 类添加 getter 以返回 impl 指针是否被认为是不好的做法?为什么?

我的库的客户端无论如何都无法使用 impl obj,因为它的接口是非公开的。另一方面,我的库内部代码现在可以在 impl obj 上进行操作。

公共.h:

class PublicClass{
    struct Impl;
    Impl* m_impl;
public:
    Impl* getImpl();
};
Run Code Online (Sandbox Code Playgroud)

实现.h:

struct Impl{
    int foo();
};
Run Code Online (Sandbox Code Playgroud)

主要.cpp:

#include "public.h"
#include "impl.h"

int main(){
    PublicClass p;
    auto pimpl = p.getImpl();
    auto interestingVal = pimpl->foo();
}
Run Code Online (Sandbox Code Playgroud)

只是一个设计问题。

c++ pimpl-idiom

5
推荐指数
1
解决办法
223
查看次数

CMake:静态库的传递依赖链接“就地”而不是附加

标题可能有点太短,不够清晰。

我们有一个复杂的 C/C++ 项目,它是在许多单独的目标中作为静态库构建和链接的。所以我的问题是 target_link_libraries 进行传递链接,但顺序错误。我需要另一个订单,因为我们使用 PIMPL 并且实现没有任何要包含的标头。它们只包含定义 PIMPL 标头并声明 Impl 对象的库的标头。但为了正确链接,它们需要链接在为 Pimpl 提供标头的 lib 之后。这不会发生。

仅当我们使用用于单元测试框架的 gcc 编译器和链接器进行构建时,才会出现这种情况。对于我们的目标项目,我们使用 TI clang-toolchain,它提供了链接器选项 --reread_libs,可以自动解决此问题。据我所知,这在 gcc 中不可用。

现在更详细地介绍一下 Cmake。该项目太大,无法做一个最小的例子,但我会尝试描述问题并将其缩小为问题:

所以我们在一个模块中有多个静态库:

# static libs inside the platform
add_library(memutils memutils/ForwardDeclaredStorage.hpp)
target_include_directories(memutils INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/memutils)

set_target_properties(memutils PROPERTIES LINKER_LANGUAGE CXX)

# contains the Pimpl-Headers to use, here task and mutex as extract
add_library(osal osal/mutex.hpp osal/task.hpp osal/TaskManager.hpp osal/TaskManager.cpp) 
target_include_directories(osal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/osal)

target_link_libraries(osal PUBLIC memutils)

add_library(system sys/system.hpp sys/system.cpp)

target_link_libraries(system PUBLIC osal)

target_include_directories(system PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/sys)
add_library(platformlib INTERFACE)
# example with INTERFACE …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom cmake

5
推荐指数
1
解决办法
89
查看次数

C++:创建共享对象而不是对象的共享指针

boost :: shared_ptr真让我烦恼.当然,我理解这种事情的实用性,但我希望我可以使用它shared_ptr<A> 作为一个A*.请考虑以下代码

class A
{
public:
    A() {}
    A(int x) {mX = x;}
    virtual void setX(int x) {mX = x;}
    virtual int getX() const {return mX;}
private:
    int mX;
};


class HelpfulContainer
{
public:
    //Don't worry, I'll manager the memory from here.
    void eventHorizon(A*& a)
    {
        cout << "It's too late to save it now!" << endl;
        delete a;
        a = NULL;
    }
};


int main()
{
    HelpfulContainer helpfulContainer;

    A* a1 = new A(1); …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom smart-pointers shared-ptr

4
推荐指数
1
解决办法
606
查看次数

没有朋友声明的Pimpl习语和内部对象协作

我正在使用pimpl习语实现几个类,并且遇到了一些设计问题.

首先,我总是看到像这样的pimpl

class Object
{
public:
    Visible();
    ~Visible();
 .. etc ..
private:
    class ObjectImpl *_pimpl;
};
Run Code Online (Sandbox Code Playgroud)

我有几个类使用这种方法,我的问题是这些类中的几个需要访问彼此的实现细节,但_pimpl指针是私有的delcared.

任何人都可以看到声明_pimpl公开的缺点.显然,如果它是公开的,那么有人可能会意外(或故意)重新分配它.(我忽略了这样一个事实,即"私人"可能被#defined定义为"公共"并且无论如何都会授予访问权限.如果你这样做,那么你应该得到你得到的东西).

我很欣赏我的设计可能存在缺陷,并欢迎任何评论.

我真的不喜欢使用朋友,我不确定他们甚至会帮忙,因为你不能在没有完全定义Object的情况下转发声明Object :: ObjectImpl.

 ...
 private:
    class ObjectImpl *_pimpl;
    friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};
Run Code Online (Sandbox Code Playgroud)

谢谢马克.

*更新 - 更多细节**

我有两个类,一个叫做Command,另一个叫做Results.我在Command上有方法返回结果向量.

命令和结果都使用了pimpl习语.我希望结果的界面尽可能小.

class Command
{
public:
    void getResults( std::vector< Results > & results );
    void prepareResults( std::vector< Results > & results );
private:
    class CommandImpl *_pimpl;
};

class Results
{
public:
    class ResultsImpl;

    Results( ResultsImpl * pimpl …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom friend shared-ptr

4
推荐指数
1
解决办法
2637
查看次数

带有模板类的pimpl习语是否有任何优势?

我的理解是,pimpl习惯用法的主要好处是隐藏实现文件中的数据成员而不是标题.但是,模板需要在头文件中完全定义,以便编译器按需实例化它们.在这种情况下,使用pimpl习惯用于模板化课程是否有任何优势?

c++ templates pimpl-idiom

4
推荐指数
1
解决办法
1116
查看次数

隐藏库用户的库依赖项

考虑一下我正在写一个静态库.让它有一个班级Foo

// mylib.h
#include <dependency_header_from_other_static_library.h>

class Foo {
    // ...
private:
    type_from_dependent_library x;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这个库(让它调用它mylib)取决于另一个库.它汇编得很好.但是当用户编译它的代码(使用Foo和包含mylib.h)并与我的lib链接时,编译失败,因为用户也需要有dependency_header_from_other_static_library.h头文件来编译代码.

我想隐藏用户的这种依赖.怎么做到这一点?想到的一件事是PIMPL成语.喜欢:

// mylib.h
#include <dependency_header_from_other_static_library.h>

class Foo {
    // ...
private:
    class FooImpl;
    boost::shared_ptr<FooImpl> impl_;
}

// mylib_priv.h
class FooImpl {
    // ...
private:
    type_from_dependent_library x;
}
Run Code Online (Sandbox Code Playgroud)

但是,它需要我来复制类的接口FooFooImpl.而且,PIMPL在我的案例中使用是否过度杀伤?

谢谢.

c++ dependencies pimpl-idiom static-libraries

4
推荐指数
1
解决办法
755
查看次数

D编程语言中的Pimpl-idiom

D拥有一个出色的模块系统,与C++相比,它可以大大缩短编译时间.根据文档,D仍然提供不透明的结构和联合,以便启用pimpl习语.我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它?那是什么语法?

在C++中,标题看起来像这样

struct S { 
    ... 
    struct Impl; 
    Impl * p; 
};
Run Code Online (Sandbox Code Playgroud)

并且实现文件(cpp-file)将使用一些有趣的::-syntax,如下所示:

#include "header.h"
struct S::Impl { 
    ... 
};
Run Code Online (Sandbox Code Playgroud)

如何在D中实现相同的功能?

d pimpl-idiom

4
推荐指数
1
解决办法
289
查看次数