标签: pimpl-idiom

类内将不完整类型的 unique_ptr 初始化为 nullptr 时,gcc 编译错误

我正在使用 pimpl idiom 和 unique_ptr 编写一些代码。当我尝试使用类内初始化将 unique_ptr 默认设置为 nullptr 时,gcc 给出了编译错误,而 clang 和 msvc 都成功编译了代码。如果我没有使用类内初始化,错误就会消失。

\n\n
// A.h\n#pragma once\n\n#include <memory>\n\nusing namespace std;\n\nclass B;\nclass A\n{\nprivate:\n    ////////////////////////\n    // here gives the error!\n    ////////////////////////\n    unique_ptr<B> impl{nullptr}; // error only with gcc, \n                                 // ok with clang and msvc\n    unique_ptr<B> impl2; // ok with all three\n\npublic:\n    A();\n    ~A();\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n
// A.cpp\n#include "A.h"\n\nclass B\n{\nprivate:\n    int b{5};\n\npublic:\n    B() = default;\n    ~B() = default;\n};\n\nA::A() = default;\nA::~A() = default;\n
Run Code Online (Sandbox Code Playgroud)\n\n
// main.cpp\n#include "A.h"\n\nint main()\n{\n    A a;\n    return 0;\n}\n …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom unique-ptr in-class-initialization gcc8

3
推荐指数
1
解决办法
440
查看次数

Pimpl不工作

这是一个非常无聊的错误,但我不知道这里发生了什么.

有大量的pimpl例子,但我不明白为什么这不起作用(这或多或少的例子之一,但我没有看到差异).

我有一个非常简单的Pimpl示例,但它不会工作.

// Foo.hpp
#include <boost/scoped_ptr.hpp>

class Foo
{
 struct Bar;
 //boost::scoped_ptr<Bar> pImpl;
 Bar* pImpl;

public:
 Foo();
 ~Foo() {}

 int returnValue();

private:

};
Run Code Online (Sandbox Code Playgroud)

// Foo.cpp
#include "foo.hpp"

struct Foo::Bar
{ 
 Bar() {}
 ~Bar() {}
 int value;
};

Foo::Foo() : pImpl(new Bar())
{
 pImpl->value = 7;
}

int Foo::returnValue() {
 return *pImpl->value;
}
Run Code Online (Sandbox Code Playgroud)

编译这个给了我错误.C2100:非法间接.

谢谢.

c++ pimpl-idiom

2
推荐指数
1
解决办法
699
查看次数

C++:创建模板化的Shared <T>对象而不是shared_ptr <T>对象

根据我之前的问题,我希望a boost::shared_ptr<A>实际上是A(或许是A*)的子类,以便它可以用在A*作为参数的方法中.

考虑以下课程:

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

在上一个问题中,我提议创建一个SharedA对象来处理这个问题,并且可能是这样做的.

class SharedA : public A
{
public:
    SharedA(A* a) : mImpl(a){}
    virtual void setX(int x) {mImpl->setX(x);}
    virtual int getX() const {return mImpl->getX();}
private:
    boost::shared_ptr<A> mImpl;
};
Run Code Online (Sandbox Code Playgroud)

如果我可以创建一个模板类来为我处理所有这些问题,那将是Grrrrrrrrreat想的.

template <class T>
class Shared : public T
{
public:
    SharedT(T* t) : mImpl(t) …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom shared-ptr

2
推荐指数
1
解决办法
224
查看次数

Pimpl与派生类中的std :: unique_ptr

我无法理解以下情况.它是关于使用基于std::unique_ptr派生类的pimpl习语.给定一个简单的类层次结构声明如下:

class Foo
{
public:
  virtual ~Foo(); 
  //...
};

struct X;

class Bar : public Foo
{
public:
  ~Bar();
  //...

private:
  std::unique_ptr<X> _d;
};
Run Code Online (Sandbox Code Playgroud)

我只显示与我的问题相关的代码.

想象一下,类Foo是一些接口,而类'Bar'是实现它的.我想用pimpl成语Bar.析构函数是虚拟的,并在相应的cpp文件中定义.此外struct X,只有前向声明的完整定义可以在cpp中访问,因此可以实例化析构函数的Bar析构函数std::unique_ptr<X>::~unique_ptr().当我尝试创建一个实例时Bar,我希望它能够工作

int main()
{
  Bar b;
}
Run Code Online (Sandbox Code Playgroud)

相反,我得到编译错误使用未定义类型'X'后跟消息无法删除不完整类型(在Visual Studio 2013 Update 2中).但是,如果我显式添加默认构造函数Bar,则main()正确编译/构建.

class Foo
{
public:
  virtual ~Foo(); 
};

struct X;

class Bar : public Foo
{
public:
  Bar();
  ~Bar();

private:
  std::unique_ptr<X> …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom c++11

2
推荐指数
1
解决办法
455
查看次数

使用智能指针继承的pimpl

请参阅我继承的PIMPL实现.在派生类中,DerivedImpl继承自BaseImpl.

问题:指向Impl的指针是否只在基类中定义,如下面的代码?如果是这样,每次我需要使用基指针时,我必须将它转换为派生类型.但是,根据分析结果静态转换shared_ptr看起来很昂贵,因为这种强制转换被广泛使用.并且转换函数不能在标题中内联,因为它在那里是不完整的.

也许我犯了一些错误.或者使用智能指针有更好的实现吗?

// Base.h
class BaseImpl; // pre-declaration

class Base
{
public:
    Base();
    explicit Base(BaseImpl* ptr);
    ~Base();

protected:
    std::shared_ptr<BaseImpl> d_Ptr;
};
Run Code Online (Sandbox Code Playgroud)
// baseimpl.h
class BaseImpl
{
    double mDate;
};
Run Code Online (Sandbox Code Playgroud)
// Derived.h
#include "Base.h"

class DerivedImpl;

class Derived :
    public Base
{
public:
    Derived();
    ~Derived();

    std::shared_ptr<DerivedImpl> d_func();
    const std::shared_ptr<DerivedImpl> d_func() const;
};
Run Code Online (Sandbox Code Playgroud)
// Derived.cpp
#include "Derived.h"
#include "DerivedImpl.h"

Derived::Derived() : Base(new DerivedImpl())
{
}

Derived::~Derived()
{
}

std::shared_ptr<DerivedImpl> Derived::d_func()
{
    return std::static_pointer_cast<DerivedImpl>(d_Ptr);
}

const std::shared_ptr<DerivedImpl> Derived::d_func() const
{
    return std::static_pointer_cast<DerivedImpl>(d_Ptr); …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance pimpl-idiom

2
推荐指数
1
解决办法
1507
查看次数

PIMPL 成语 VS 前向声明

我已经阅读了一些关于 PIMPL 习惯用法的内容并且想知道 - 转发声明依赖类型有什么不同吗?

如果是这样的话:

  • 我什么时候更喜欢使用它而不是前向声明?
  • 这两个版本的编译时间不同吗?
  • 其中一个比另一个更具可扩展性吗?

特别考虑一个Foo依赖于Bar(应该有一个 type 成员)的类Bar

Foo.h 带有前向声明:

class Bar;

class Foo
{
public:
    Foo();

private:
    Bar* _bar;
};
Run Code Online (Sandbox Code Playgroud)

Foo.h 与 PIMPL:

class Foo
{
    public:
        Foo();

    private:
        /* FooImpl is an incomplete type at this point.
         * Implemented in cpp file and has a member of type Bar.
         */
        class FooImpl;  

        FooImpl* _fooImpl;
}
Run Code Online (Sandbox Code Playgroud)

请忽略原始指针的使用 - 我只是想说明一点

c++ pimpl-idiom

2
推荐指数
1
解决办法
1329
查看次数

使用匿名命名空间结构的pimpl习语:这样安全吗?

我的队友经常使用pimpl的变体,他喜欢这样:

foo.h中:

namespace { struct Impl; }

class Foo
{
public:
  Foo();
  ~Foo();

  void Bar(int n);
  /* ... */

private:
  std::unique_ptr<Impl> _impl;
};
Run Code Online (Sandbox Code Playgroud)

这里发生的事情是他正在声明实现类在匿名命名空间中.然后他将Impl在Foo.cpp中定义类.

因此,结构的定义::Impl将可供Foo.cpp翻译单位使用.其他代码包含Foo.h会引发警告,因为它们显然无法访问::Impl定义的内容Foo.cpp.但是,我们不需要它们 - 它只是一个Foo.cpp只用于它的类; 我们不希望它在其他地方可见或已知.

虽然我们当然可以在.cpp文件中包含多个标题,每个标题都声明自己的::Impl结构,但实际上并没有发生冲突,因为结构永远不会在各自的翻译单元之外使用.

tl; dr:这看起来很奇怪,引发警告,看起来好像会引起冲突,但似乎确实有效.


所有这一切,我不满意我的代码中提出了一些警告,这些警告已经深入到我们的代码中(这个文件越多,它就越难以取出.)这也只是一大堆警告.

我的队友坚持这一点,因为它很简单,保持代码定义简单,并允许我们Impl在所有代码中使用简短,一致的类名.

我不是编码惯例的坚持者; 如果这是我们用例的好习惯,我不介意.但是我觉得这是安全和可维护的,并且在某些时候不会在我们的脸上爆炸.

c++ namespaces pimpl-idiom incomplete-type

2
推荐指数
1
解决办法
177
查看次数

Pimpl成语作为模板基类

我目前正在研究pimpl习惯用法,并且有很好的教程介绍如何实现它(例如here)。但我从未见过将其实现为这样的基本模板类:

#ifndef PIMPL_H
#define PIMPL_H

template <class T>
class Pimpl
{
public:
    explicit Pimpl();
    explicit Pimpl(T *ptr);
    virtual ~Pimpl() = 0;

    Pimpl(const Pimpl<T> &other);
    Pimpl &operator=(const Pimpl<T> &other);

protected:
    T *d_ptr;
};

template<class T>
Pimpl<T>::Pimpl() : d_ptr(new T)
{

}

template<class T>
Pimpl<T>::Pimpl(T *ptr) : d_ptr(ptr)
{

}

template<class T>
Pimpl<T>::~Pimpl()
{
    delete d_ptr;
    d_ptr = 0;
}

template<class T>
Pimpl<T>::Pimpl(const Pimpl<T> &other) : d_ptr(new T(*other.d_ptr))
{

}

template<class T>
Pimpl<T> &Pimpl<T>::operator=(const Pimpl<T> &other)
{
    if …
Run Code Online (Sandbox Code Playgroud)

c++ templates pimpl-idiom

2
推荐指数
1
解决办法
691
查看次数

PIMPL 类的 setter 应该是 const 成员函数吗?

我经常使用“指向私有实现的指针”类。这些类的 setter 方法在技术上可以是 const 成员函数,例如:

class MyPrivateClass
{
public:
  int something = 1;
};

class MyClass
{
public:

  // TODO: initialize pointer in constructor
  // TODO: delete pointer in destructor

  // Note how this setter is const!
  void setSomething(int something) const
    {
      p->something = something;
    }

private:
  MyPrivateClass* p;
};

int main()
{
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是可能的,因为编译器只强制按位常量,而不是逻辑常量,所以上面的代码应该编译得很好。

我认为这些setter方法应该为const成员函数,让来电者知道对象实际上是被修改(修改逻辑,而不是按位体改,由于指针实现)。

我的问题是:

是否有充分的理由使这些 setter 方法成为 const 成员函数?

Effective C++ 建议(在第 3 项中)尽可能始终使用 const,但我认为这不适用于我的示例。

c++ pimpl-idiom

2
推荐指数
1
解决办法
367
查看次数

是否可以将右值引用用作pimpl句柄?

我想用Pimpl(私有实现)创建一个类。通常,您会这样做:

class A
{
private:
  class B;
  B* _pimpl = nullptr;
}
Run Code Online (Sandbox Code Playgroud)

然后在.cpp文件中定义它。但是我必须使用动态分配。可以改用右值引用吗?

class A
{
public:
  A(); //Constructor to init rvalue reference
private:
  class B;
  B&& _pimpl;
}
Run Code Online (Sandbox Code Playgroud)

然后在.cpp文件中:


class A::B
{
public:
   int C = 3u;
}

//and then the constructor of A:

A::A() : _pimpl(B()) { } //now we should have a fresh b pimpl?

Run Code Online (Sandbox Code Playgroud)

我目前正在放假,只有C ++书籍可供参考。我阅读了有关右值引用的内容,并认为它可能有效。你们有什么感想?

c++ pimpl-idiom reference rvalue-reference c++11

2
推荐指数
1
解决办法
74
查看次数