Skip to content

Questions about the precondition of std::any's assignment operators #5698

@achabense

Description

@achabense

In #3965, I tried to fix std::any's self-assignment. The obvious way is to compare the address first, but I chose a different design (by always making a copy first) to support the if(1) case below.

The implementation cannot be as efficient as address comparison. And worse, I find that any::swap is implemented based on std::exchange, which calls operator=(any&&) inside. As a result, that PR made any::swap(any&) a lot less efficient.

// What's the precondition of any-assignment and swap?
void scenarios() {
    std::any a = std::make_any<std::any>(42);
    std::any& a_o = *std::any_cast<std::any>(&a);
    if (1) { // Should this be supported?
        a = std::move(a_o);
        assert(std::any_cast<int>(a) == 42);
    } else { // And what about this?
        a_o = std::move(a);
    }
    // And these?
    // a.swap(a_o);
    // a_o.swap(a);
}

So the question is, what's the precondition for std::any's swap and assignment operators? Should we really support those use cases, i,e. can we just compare the address directly?

Even if we cannot compare the address, I think we should still try to improve any::swap. By inlining the code, it turns out at least one copy is unnecessary.

Related:

The test case added in the original PR, and another PR trying to fix self-assignment:
#5413
https://github.com/microsoft/STL/pull/3965/files#diff-a0f3b054031c8ff90d8a2ad3fc1903f67bb1477d1a1fbf4217c02b55d2301dbe

The current implementation of operator= and swap:

STL/stl/inc/any

Lines 183 to 186 in 37d575e

any& operator=(any&& _That) noexcept {
_Assign(_STD move(_That));
return *this;
}

STL/stl/inc/any

Lines 232 to 234 in 37d575e

void swap(any& _That) noexcept {
_That = _STD exchange(*this, _STD move(_That));
}

https://eel.is/c++draft/any.assign#4.sentence-1

any& operator=(any&& rhs) noexcept;
Effects: As if by any(std​::​move(rhs)).swap(*this)[.](https://eel.is/c++draft/any.assign#4.sentence-1)

https://eel.is/c++draft/any.modifiers#19.sentence-1

void swap(any& rhs) noexcept;
Effects: Exchanges the states of *this and rhs[.](https://eel.is/c++draft/any.modifiers#19.sentence-1)

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions