C++ std::unique\u ptr没有合适的默认构造函数

C++ std::unique\u ptr没有合适的默认构造函数,c++,sdl,unique-ptr,C++,Sdl,Unique Ptr,这是我上一篇文章的延续。因为它已经关闭了,我决定做一个新的职位。我删除了一半代码以使其更具可读性 我读到的一些帖子: 类cGraphics { 公众: //创建者功能 std::unique_ptr Create_窗口(intxwin、intywin); //ctor&dtor cGraphics():m_窗口(nullptr,SDL_窗口){} cGraphics(int xWin、int yWin); ~cGraphics(); 私人: std::唯一的\u ptr m\u窗口; };

这是我上一篇文章的延续。因为它已经关闭了,我决定做一个新的职位。我删除了一半代码以使其更具可读性

我读到的一些帖子:

类cGraphics
{
公众:
//创建者功能
std::unique_ptr Create_窗口(intxwin、intywin);
//ctor&dtor
cGraphics():m_窗口(nullptr,SDL_窗口){}
cGraphics(int xWin、int yWin);
~cGraphics();
私人:
std::唯一的\u ptr m\u窗口;
};
cGraphics::cGraphics(intxwin,intywin)
{
m_Window=std::move(创建_Window(xWin,yWin));
if(m_Window==nullptr)
{
抛出“SDL_窗口或SDL_渲染器未就绪!”;
}
}
cGraphics::~cGraphics()
{
IMG_Quit();
SDL_退出();
}
std::unique_ptr cGraphics::创建_窗口(intxwin,intywin)
{
返回std::unique_ptr(SDL_CreateWindow(“SDL窗口”,SDL_WINDOWPOS_未定义,SDL_WINDOWPOS_未定义,xWin,yWin,显示SDL_Window_),SDL_DestroyWindow);
}
编译器抱怨:

'std::unique_ptr<SDL_Window,void (__cdecl *)(SDL_Window *)>::unique_ptr': no appropriate default constructor available
“std::unique\u ptr::unique\u ptr”:没有合适的默认构造函数可用
我知道,当编译器找不到某些成员的默认构造函数时,通常会出现此错误。但是这不是真的,因为我明确声明了
std::unique\u ptr
的默认值

如果编译器实际上在抱怨
SDL\u Window
,这是一个不完整的类型(C结构),我该怎么办?

a
std::unique\u ptr
不是默认的可构造类型。这意味着

cGraphics::cGraphics(int xWin, int yWin) ***
{
    m_Window = std::move(Create_Window(xWin, yWin));

    if (m_Window == nullptr)
    {
        throw "SDL_Window or SDL_Renderer not ready!";
    }
}
当您到达部分
***
时,编译器将尝试默认构造
m_窗口
,因为您在成员初始化列表中没有这样做。从编译器ro默认构造
m_窗口
进行的尝试是导致错误的原因。我们可以通过移动
m_Window=std::move(Create_Window(xWin,yWin))来解决这个问题从构造函数体中取出,并将其放入成员初始化列表中,如

cGraphics::cGraphics(int xWin, int yWin) : m_Window(Create_Window(xWin, yWin))
{   
    if (m_Window == nullptr)
    {
        throw "SDL_Window or SDL_Renderer not ready!";
    }
}
如果您不想这样做,那么可以委托给默认构造函数,然后像最初那样分配给
m_Window
。那看起来像

cGraphics::cGraphics(int xWin, int yWin) : cGraphics()
{
    m_Window = Create_Window(xWin, yWin);

    if (m_Window == nullptr)
    {
        throw "SDL_Window or SDL_Renderer not ready!";
    }
}

以下是您如何定义您的
唯一\u ptr

std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> m_Window;

您不需要在那里执行
std::move
CreateWindow
函数已经返回一个临时值。旁白:
std::move
在所有这些代码位中都是不必要的。@SergeyA我已经删除了这些移动,没有发现它们是多余的,谢谢。至于授权为什么有效,这是因为OP在默认构造函数中正确地初始化了指向
nullptr
的指针。@NathanOliver,我在键入注释后(甚至在grace窗口中删除了我愚蠢的证据!):事实上,@NicholasHumphrey,初始化器列表比委派构造函数更优雅。除此之外,考虑手动定义自己的DELTER(<代码> StuttJooKySDLyDebug窗口{空操作程序())(SDLVILL**P),除了{SDLyDebug窗口(P);},<代码> >使用它,而不是拖拉其他指针,间接地通过它们。@Deduplicator所说的是非常正确的<带有deleter函数指针的code>std::unique_ptr
的大小是没有deleter函数指针的两倍。这是浪费空间。您正在拖拽一个从未更改的额外指针,这也使得编译器更难进行优化(它可能无法判断deleter函数从未更改)。如果这太痛苦了(依我看是这样),那么编写一个简单的包装器,从函数指针创建一个删除器:(C++17,但你可以在它之前接近该语法)@Justin:或者可能更容易:
template inline void std::default_delete::operator()(SDL_Window*p)const{SDL_destroy Window(p);}
@处于允许范围边界的重复数据消除程序。我强烈建议不要这样做。这使得犯错误非常容易。考虑< <代码> SDLWILL**/COD>是如何由<代码> SDLFCREATIOLWindows < /代码>创建的,而不是通过<代码>新SDLWindows窗口;<代码>。因此,在编写代码之后,如果编写了
std::make_unique(…)
,您将有未定义的行为。简单地说,这非常容易搞砸。@Justin:As
SDL\u Window
不完整,调用
std::make\u unique
将导致编译错误。那里没有危险。
std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> m_Window;
cGraphics::cGraphics(int xWin, int yWin) : 
                     m_Window{Create_Window(xWin, yWin)} {...}