c++ - 暗示返回值不被存储的方法

标签 c++ c++17 methodology

我们可以使用nodiscard属性来暗示函数的返回值不应被丢弃。是否有任何属性(或其他方式)来暗示一些相反语义:函数的返回值只能临时使用(我的意思是“临时”,不分配给除本地变量之外的任何变量)?

由于目的可能不会立即明确,请考虑我有一个类 FooHolder 来保存资源 Foo;调用 FooHolder::getFoo() 返回当前持有的 Foo:

#include <memory>

class Foo {
public:
    Foo& bar() { /* do something */ return *this; }
    const Foo& far() const { /* do something else */ return *this; }
};

class FooHolder {
private:
    std::shared_ptr<Foo> _foo { nullptr };

public:
    FooHolder(): _foo(std::make_shared<Foo>()) {}

    Foo& getFoo() { return *_foo; }
    const Foo& getFoo() const { return *_foo; }
};

我们可以通过多种方式使用它:

// Others may try storing some status:
Foo* g_foo = nullptr;

int main() {
    FooHolder foo_holder {};

    // I want to support this:
    foo_holder.getFoo().bar().far() /* chained calls... */ ;

    // Also, maybe this:
    auto& local_foo = foo_holder.getFoo();
    local_foo.bar();
    local_foo.far();

    // But not this, because the Foo instance that FooHolder holds may perish:
    static Foo& static_foo = foo_holder.getFoo();

    // Nor this:
    g_foo = &local_foo;

    return 0;
}

那么有没有办法阻止(或至少警告)存储 FooHolder::getFoo() 的返回值?或者,通过引用返回资源是不好的做法吗?

最佳答案

[...] is it bad practice to return resources by reference?

这要看情况。有很多返回非常量引用的方法的示例,它们都很好。例如,考虑标准容器元素访问器。然而,它们并不用于封装。 std::vector::operator[] 并不是要向调用者隐藏元素,而是要提供对其的直接访问。返回非常量引用不是封装!事实恰恰相反。请注意,std::vector 甚至授予您对其 data() 的访问权限。这也不是封装,它依赖于用户不delete[] some_vect.data()或做其他会破坏 vector 的错误事情。

您希望 FooHolder 封装所包含的 Foo

这是相反的要求。

您基本上有两个选择:A) 调用者知道他们在做什么。他们阅读文档。他们知道不应该以错误的方式使用 FooHolder::getFoo。 B) 使用适当的封装:永远不要让调用者直接访问非常量 Foo:

class FooHolder {
private:
    std::shared_ptr<Foo> _foo { nullptr };

public:
    FooHolder(): _foo(std::make_shared<Foo>()) {}

    // nope // Foo& getFoo() { return *_foo; }
    // maybe // const Foo& getFoo() const { return *_foo; }
    
    FooHolder& bar() { 
            _foo->bar();
            return *this;
    }
    // ..same for far() ...
};

请注意,A) 是一个可行的解决方案。考虑一下像 std::shared_ptr 这样的东西也可能被错误地使用。用户应该知道如何正确使用它。不同之处在于 std::shared_ptr 是一个标准类型,具有大量文档。因此,如果这是正确的选择,您应该三思而后行。


So are there ways to prevent (or at least warn about) storing the return value of FooHolder::getFoo()?

没有。一旦你返回了一个非常量引用,所有的赌注都会被取消。 FooHolder 不再控制调用者可以使用该引用执行哪些操作。您可以阻止复制或移动,但无法阻止保留引用。

关于c++ - 暗示返回值不被存储的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71077172/

相关文章:

c++ - 从C++更改QML图像源

c++ - 从 std::vector c++ 调用 std::function 时崩溃

c++ - 将结构转换为 uint8_t 的 constexpr 数组

c++ - T declval() 而不是 T && declval() for common_type

使用远程 shell 访问进行 PHP 调试

c++ - 哪些类型的头文件不应该受到多重包含的保护?

c++ - 如何在 C++ 中返回本地数组?

c++ - 在 (Neo)vim 中调试 C++

.net - 部署 .NET 框架的要求

testing - 你如何证明一个函数有效?