C26415 SMART_PTR_NOT_NEEDED

"Smart pointer parameter is used only to access contained pointer. Use T* or T& instead."

C++ Core Guidelines: R.30: Take smart pointers as parameters only to explicitly express lifetime semantics

Using a smart pointer type to pass data to a function indicates that the target function needs to manage the lifetime of the contained object. However, if the function only uses the smart pointer to access the contained object and never actually calls any code which may lead to its deallocation (never affect its lifetime), there is usually no need to complicate the interface with smart pointers. A plain pointer or reference to the contained object should be preferred.

Remarks

  • This check is a covers majority of scenarios that also causes C26410, C26415, C26417, and C26418. It is better to cleanup SMART_PTR_NOT_NEEDED first and then switch to edge cases for shared or unique pointers. For more focused cleanup this warning can be disabled.
    • In addition to the standard std::unqiue_pointer and std::shared_pointer templates, this check recognizes user defined types which are likely intended to be smart pointers. Such types are expected to define the following operations:
    • overloaded dereference or member access operators, that are public and not marked as deleted;
    • public destructor which is neither deleted nor defaulted. This includes destructors which are explicitly defined empty.
    • Interpretation of the operations that can affect lifetime of contained objects is quite broad and includes:
    • any function which accepts pointer or reference parameter to a non-constant smart pointer;
    • copy or move constructors or assignment operators;
    • non-constant functions. ## Example cumbersome lifetime management
bool set_initial_message(
            const std::unique_ptr<message> &m) // C26415, also C26410 NO_REF_TO_CONST_UNIQUE_PTR
{
    if (!m || initial_message_)
        return false;

    initial_message_.reset(m.get());
    return true;
}

void pass_message(const message_info &info)
{
    auto m = std::make_unique<message>(info);
    const auto release = set_initial_message(m);
    // ...
    if (release)
        m.release();
}

Example

cumbersome lifetime management - reworked

void set_initial_message(std::shared_ptr<message> m) noexcept
{
    if (m && !initial_message_)
        initial_message_ = std::move(m);
}

void pass_message(const message_info &info)
{
    auto m = std::make_shared<message>(info);
    set_initial_message(m);
    // ...
}