暗示 return 值不打算存储的方法

Ways to imply return values are not meant to be stored

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

由于目的可能不是很清楚,假设我有一个 class FooHolder 来保存资源 Foo;调用 FooHolder::getFoo() return 的 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() 的 return 值?或者,通过引用 return 资源是不好的做法吗?

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

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

您希望FooHolder封装包含的Foo

这是相反的要求。

你基本上有两个选择:A) 呼叫者知道他们在做什么。他们阅读文档。他们知道他们不应该以错误的方式使用 FooHolder::getFoo。 B)使用适当的封装:永远不要让调用者直接访问 non-const 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()?

没有。一旦您 return 编辑了 non-const 参考资料,所有赌注都将取消。 FooHolder 不再控制调用者可以对该引用执行的操作。您可以阻止复制或移动,但不能阻止引用。