Description
I may have copy/move constructors that take an additional allocator argument. Additionally, the type may use the leading-allocator convention with std::allocator_arg_t
.
If I call one of these "extended" copy/move constructors in my copy/move-and-swap idiom, bugprone-unhandled-self-assignment
doesn't recognize it and produces a false positive warning (copy-and-swap/move should not trigger the warning).
A rough test:
// REQUIRES: static-analyzer
// RUN: clang-tidy -checks='-*,bugprone-unhandled-self-assignment' %s --
namespace std {
namespace pmr {
template <typename TYPE = void>
class allocator {};
}
struct allocator_arg_t {} allocator_arg;
};
#define LEADING_STYLE 1
class MyValueType
{
// pointer member to trigger bugprone-unhandled-self-assignment
void *foo = nullptr;
public:
using allocator_type = std::pmr::allocator<>;
MyValueType(const MyValueType& other)
{
}
#ifdef LEADING_STYLE
MyValueType(std::allocator_arg_t, const allocator_type& alloc, const MyValueType& other)
{
}
#else
MyValueType(const MyValueType& other, const allocator_type& alloc)
{
}
#endif
#ifdef LEADING_STYLE
// CHECK-NOT: warning
MyValueType& operator=(const MyValueType& other)
{
MyValueType tmp(std::allocator_arg, get_allocator(), other);
swap(tmp);
return *this;
}
#else
// CHECK-NOT: warning
MyValueType& operator=(const MyValueType& other)
{
MyValueType tmp(other, get_allocator());
swap(tmp);
return *this;
}
#endif
void swap(MyValueType& other) noexcept {
}
allocator_type get_allocator() const {
return allocator_type();
}
};
Though we're hitting this in our own code, there are examples of these patterns in the standard with e.g. https://en.cppreference.com/w/cpp/container/vector.html which has a trailing allocator overload for its copy ctor and https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2047r5.html for a pmr-aware optional which uses the leading allocator style.
Note that since we call swap
we must ensure the tmp
we swap with uses the same allocator as us, hence the call to the extended version passing our own allocator.
Also, the allocator_type
could be templated in the general case.