c++functionlanguage-lawyerdestructorprivate

Can one pass by value an object with private destructor in a function?


If a class has inaccessible (private) destructor, can it be passed by value to a function as in the following example?

class A {
    ~A() {}
};

// ok in GCC and Clang, error in MSVC
void f(A) {}

GCC and Clang both accept this program, while MSVC rejects it with the error:

<source>(6): error C2248: 'A::~A': cannot access private member declared in class 'A'

Online demo: https://gcc.godbolt.org/z/884176rWW

Which compiler is correct here, according to the standard, or is it not specified?


Solution

  • [expr.call]p6:

    It is implementation-defined whether a parameter is destroyed when the function in which it is defined exits ([stmt.return], [except.ctor]) or at the end of the enclosing full-expression; parameters are always destroyed in the reverse order of their construction. The initialization and destruction of each parameter occurs within the context of the full-expression ([intro.execution]) where the function call appears.
    [Example 2: The access ([class.access.general]) of the constructor, conversion functions, or destructor is checked at the point of call. [...] — end example]

    Microsoft chooses to destroy arguments in the callee (i.e., the code for f would include a call the the destructor of A), but it erroneously also does the access check there.

    Access checks should only be done in the callee. If you called the function somewhere the destructor was accessible:

    class A {
        ~A() {}
        friend int main();
    };
    
    void f(A) {}
    
    int main() {
        f(A{});
    }
    

    This should compile, even if the implementation actually destroys the parameter inside f.