Document Number

P1077R0

Date

2018-05-04

Project

Programming Language C++

Audience

Evolution Working Group

Summary

This proposal removes the requirement for literal types to not have virtual destructors

Table of Contents

Motivation

Virtual destructors are currently non-trivial, by definition ([class.dtor] p6). This is overly strict.

The informal meaning of trivial here is "has no observable effects and can be omitted", but there are two contexts in which this question can be asked. First, whether the destructor itself has no observable effects; second, whether an expression invoking the destructor (such as p->~X()) has no observable effects.

In the first case, it doesn’t matter whether the destructor is virtual; it either has observable effects or it doesn’t, and its virtuality doesn’t change the outcome.

In the second case, it does matter. When ~X is virtual, the expression may end up invoking a derived destructor, and whether ~X itself has no effects is irrelevant.

Conflating these two meanings creates problems in two places. First, literal types are required to have trivial destructors. This needlessly prohibits types with virtual destructors from being literal. For example,

struct X1
{
    virtual int f() const;
};

is literal, but

struct X2
{
    virtual ~X2() = default;
    virtual int f() const;
};

isn’t.

Second, it classifies certain destructors as non-trivial even when they satisfy the requirement that an expression invoking them has no effects:

struct X3
{
    X2 x2;
};

~X3 in this example is not virtual and has no effects, but the transitive requirement for ~X2 to be trivial renders ~X3 nontrivial as well.

Proposed Changes

(All edits are relative to N4741.)

Change 15.4 [class.dtor] p6 as follows:

  • A destructor is quasi- trivial if it is not user-provided and if:

    — the destructor is not virtual,

    — all of the direct base classes of its class have quasi- trivial destructors, and

    — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a quasi- trivial destructor.

    Otherwise, the destructor is not quasi- trivial.

Add a new paragraph below the above one:

  • A destructor is trivial if it is quasi-trivial and it is not virtual.

Change 6.7 [basic.type] p10 bullet 10.5.1 as follows:

  • — it has a quasi- trivial destructor,

Example

The standard library provides, in [syserr], a framework for reporting error codes. This framework classifies error codes into categories, represented by singleton values of types derived from the base class error_category.

error_category, and types derived from it such as generic_category, could easily be made literal if not for the fact that ~error_category is specified as virtual. This precludes categories to be made constexpr variables, a problem this proposal solves.

The reason for the wish to make categories constexpr is subtle. Category equality is currently specified as identity comparison, this == &rhs. But there are platforms on which it’s hard to guarantee that all instances of generic_category and system_category have the same address. On such a platform it’s better for equality to be content-based rather than address-based, for instance by storing an unique identifier in the category, so that all generic_category instances compare equal.