相关疑难解决方法(0)

使用unique_ptr进行前向声明?

我发现std::unique_ptr在下面的代码中结合使用前向声明类很有用.它编译并与GCC一起工作,但整个事情似乎有点奇怪,我想知道这是否是标准行为(即标准要求)?因为B声明时B不是完整的类型unique_ptr.

A.hpp

#include <memory>

class B;

class A {
    std::unique_ptr<B> myptr;
    // B::~B() can't be seen from here
public:
    ~A();
};
Run Code Online (Sandbox Code Playgroud)

A.cpp

#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.

A::~A() = default; // without this line, it won't compile 
// however, any destructor definiton will do.
Run Code Online (Sandbox Code Playgroud)

我怀疑这与析构函数有关(因此需要调用析构函数unique_ptr<B>)是在特定的编译单元(A.cpp)中定义的.

c++ destructor forward-declaration unique-ptr

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

我如何使用unique_ptr用于pimpl?

这是我在尝试将unique_ptr用于pimpl时所看到的简化.我选择了unique_ptr,因为我真的希望类拥有指针 - 我希望pimpl指针和类的生命周期相同.

无论如何,这是标题:

#ifndef HELP
#define HELP 1

#include <memory>

class Help
{

public:

  Help(int ii);
  ~Help() = default;

private:

  class Impl;
  std::unique_ptr<Impl> _M_impl;
};

#endif // HELP
Run Code Online (Sandbox Code Playgroud)

这是来源:

#include "Help.h"

class Help::Impl
{
public:
  Impl(int ii)
  : _M_i{ii}
  { }

private:

  int _M_i;
};

Help::Help(int ii)
: _M_impl{new Help::Impl{ii}}
{ }
Run Code Online (Sandbox Code Playgroud)

我可以将它们编译成一个库就好了.但是当我尝试在测试程序中使用它时,我得到了

ed@bad-horse:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp
In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0,
                 from Help.h:4,
                 from test_help.cpp:3:
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = …
Run Code Online (Sandbox Code Playgroud)

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

60
推荐指数
2
解决办法
2万
查看次数

GotW#101"解决方案"实际上解决了什么问题吗?

首先阅读Herb's Sutters GotW关于C++ 11中pimpl的帖子:

我在理解GotW#101中提出的解决方案时遇到了一些麻烦.据我所知,在GotW#100中辛苦解决的所有问题都复仇了:

  • 的pimpl成员是外的线的模板,并且定义并不在使用点可见(在class widget的类定义和隐式生成的特殊成员函数widget).也没有任何明确的实例化.这将导致链接期间未解决的外部错误.

  • widget::impl在实例化定义的点上仍然是不完整的(我认为它实际上根本没有pimpl<widget::impl>::~pimpl()被实例化,只是被引用).因此std::unique_ptr<widget::impl>::~unique_ptr()调用delete指向不完整类型的指针,如果widget::impl有一个非平凡的析构函数,则会产生未定义的行为.

请解释是什么迫使编译器在widget::impl完成的上下文中生成特殊成员.因为我看不出它是如何工作的.


如果GotW#101仍然需要widget::~widget()在实现文件中明确定义,哪里widget::impl完成,那么请解释"更健壮"的评论(@sehe在他的答案中引用).

我看的GotW#101的核心要求是,包装"消除样板的一些作品",这在我看来(基于该段的其余部分)来表示的widget::~widget()声明和定义.所以请不要依赖于你的答案,在GotW#101中,那已经消失了!


Herb,如果你停下来,请告诉我是否可以在这里剪切+粘贴解决方案代码以供参考.

c++ pimpl-idiom incomplete-type c++11 gotw

21
推荐指数
2
解决办法
1856
查看次数

C++23 中 unique_ptr 的 nullptr init 规则是否发生变化?

此代码在 C++20 模式下使用 VS 2022 中的 MSVC 进行编译。它在 C++23 模式下失败。( /std:c++latest)

#include <memory>

struct A;

struct B {
    B();
    ~B();

    std::unique_ptr<A> ptr{nullptr};
};

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

当前版本的 GCC 和 clang 在 C++23 模式下接受此代码。

编译器资源管理器上的实时代码

C++23 模式下的 MSVC:

#include <memory>

struct A;

struct B {
    B();
    ~B();

    std::unique_ptr<A> ptr{nullptr};
};

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

微软回答我(尚未公开),新行为是由于constexpr std::unique_ptrC++23 模式造成的,他们只是遵循这个标准。

这是正确的吗?GCC 和 clang 在 C++23 模式下接受此代码是错误的吗?


我将对这里发生的情况添加更多解释,因为一些评论表明这并不明显。

std::unique_ptr<A>这里调用了的构造函数。它不会调用不完整类型的构造函数A,因为它是用nullptr. 这部分对于 C++23 模式下的 …

c++ unique-ptr visual-c++ language-lawyer c++23

13
推荐指数
0
解决办法
421
查看次数

如果 std::make_unique 从未被调用,为什么在默认成员初始化中不需要参数?

默认成员初始化需要引用现有的构造函数,无论它是否被使用过。因此,查看一个Foo没有默认构造函数的结构:

struct Foo{
    Foo(int x) : x_(x){}
    int x_;
};
Run Code Online (Sandbox Code Playgroud)

很明显,以下内容不起作用,并导致编译错误:

class Bar0{
    Foo foo = Foo(); #constructor Foo() doesn't exist
    Bar0() : foo(0){}
}
Run Code Online (Sandbox Code Playgroud)

但是,它是一个不同的故事std::unique_ptr和std::make_unique:

class Bar1{
    unique_ptr<Foo> foo = make_unique<Foo>(); #compiler doesn't complain
    Bar1() : foo(make_unique<Foo>(0)){}
}
Run Code Online (Sandbox Code Playgroud)

这是令人费解的,因为只要Bar1包含一个foo不在初始化列表中的构造函数,编译就会失败。

我可以确认这对 MSVC12 来说是正确的。可能是编译器错误吗?

c++ default initialization unique-ptr c++11

0
推荐指数
1
解决办法
2301
查看次数