首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么我们需要在C++11中使用虚拟~A() = default;而不是虚拟~A() {}?

为什么我们需要在C++11中使用虚拟~A() = default;而不是虚拟~A() {}?
EN

Stack Overflow用户
提问于 2013-06-21 03:00:35
回答 3查看 2.1K关注 0票数 49

在Stack Overflow post 中,我有这样的评论:

在C++11中,你实际上会想要做virtual ~A() = default;,否则你会丢失隐式的

构造器。

virtual ~A() = default;是用来做什么的?为什么隐式移动构造函数在virtual ~A() {}中丢失了

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-06-21 03:26:19

评论是不正确的。

两者:

代码语言:javascript
运行
复制
virtual ~A() = default;

代码语言:javascript
运行
复制
virtual ~A() {}

用户是否声明为。如果析构函数是用户声明的,则禁止隐式移动成员。

dcl.fct.def.default/p4讨论用户声明和用户提供的特殊成员:

如果特殊成员函数是用户声明的,并且在第一次声明时没有显式地默认或删除,则该函数是用户提供的。

票数 42
EN

Stack Overflow用户

发布于 2013-06-21 03:33:18

在这篇文章https://stackoverflow.com/a/17204598/260127中,我有这样的评论:

在C++11中,你实际上想要做virtual ~A() = default;,否则你会丢失隐式的移动构造器。

注释不正确。

即使是defaulted,该析构函数也是“用户声明的”(尽管请注意,它并非也是“用户提供的”)。

代码语言:javascript
运行
复制
#include <iostream>

struct Helper
{
    Helper() {}
    Helper(const Helper& src) { std::cout << "copy\n"; }
    Helper(Helper&& src)      { std::cout << "move\n"; }
};

struct A
{
    virtual ~A() {}
    Helper h;
};

struct B
{
    virtual ~B() = default;
    Helper h;
};

struct C
{
    Helper h;
};


int main()
{
    {
        A x;
        A y(std::move(x));   // outputs "copy", because no move possible
    }

    {
        B x;
        B y(std::move(x));   // outputs "copy", because still no move possible
    }

    {
        C x;
        C y(std::move(x));   // outputs "move", because no user-declared dtor
    } 
}

Live demo

  • g++-4.8 main.cpp
    • ./a.out -std=c++11 -O2 -Wall -pthread -O2

复制

复制

move

所以你并没有“丢失”任何东西--一开始就没有移动功能!

以下是在这两种情况下都禁止隐式移动构造函数的标准段落:

[C++11: 12.8/9]:如果类X的定义没有显式声明移动构造函数,则仅当且仅当

  • X没有用户声明的复制构造函数,
  • X没有用户声明的复制赋值运算符,
  • X没有用户声明的移动赋值运算符,
  • X 没有用户声明的析构函数,并且
  • 移动构造函数不会被隐式定义为已删除。

Bootnote

如果该标准的未来版本真正列出了“用户声明”等术语的确切含义,那也不会有什么坏处。至少,这是这样的:

[C++11: 8.4.2/4]: ..如果特殊成员函数是用户声明的,并且在第一次声明时没有显式地默认或删除,则该函数是用户提供的。。。

在这里,人们可以通过暗示来假设这种区别。

票数 27
EN

Stack Overflow用户

发布于 2013-06-21 03:05:46

这种评论是错误的。

不是提供你自己的移动构造函数,如果你希望编译器提供一个,其中一个要求是它希望析构函数也是由它提供的,即一个简单的析构函数。然而,当前的标准对何时可以提供隐式实现是相当严格的-接受用户如何给出析构函数。用户声明的任何内容都被认为是用户在自己手中处理问题,因此不仅如此

代码语言:javascript
运行
复制
~A() { … }

但也有这个

代码语言:javascript
运行
复制
~A() = default;

使编译器不提供隐式析构函数。第一个是定义,因此也是一个声明;第二个只是一个声明。在这两种情况下,析构函数都是用户声明的,因此禁止编译器提供隐式移动构造函数。

我猜这个要求背后的基本原理是,在移动过程中,对象的资源被移动到另一个对象,使原始对象处于动态存储中没有资源的状态;但是如果你的类没有任何这样的资源,那么它可以被简单地移动,销毁,等等。当你声明一个非平凡的析构函数时,它对编译器来说是一个提示,你在类中管理的资源不是微不足道的,你必须提供非平凡的移动,所以编译器不提供一个。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17221668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档