C++ 友元说明符的范围限制是什么

C++ 友元说明符的范围限制是什么,c++,c++11,design-patterns,proxy,friend,C++,C++11,Design Patterns,Proxy,Friend,假设我有一个对象X和一个代理。我想控制代理的生存期,以便它不能扩展到由X方法返回的临时对象之外。我不明白我这样做是否是因为标准允许 class X { public: struct Proxy { ~Proxy(); /// Implicit convertion to wrapped object. operator X &(); operator const X &() const;

假设我有一个对象
X
和一个代理。我想控制代理的生存期,以便它不能扩展到由
X
方法返回的临时对象之外。我不明白我这样做是否是因为标准允许

class X
{
public:
    struct Proxy
    {
        ~Proxy();

        /// Implicit convertion to wrapped object.
        operator X &();
        operator const X &() const;

        /// Explicit access to wrapped object.
        X & get();
        const X & get() const;

    private:
        friend class X;

        Proxy(X & x_ref);
        Proxy(Proxy && other) noexcept;

        Proxy(const Proxy &) = delete;
        Proxy & operator = (const Proxy&) = delete;
        Proxy & operator = (Proxy && other) = delete;

        X & _x_ref;
    };

    Proxy get_proxy() {
        Proxy proxy(*this);
        // ...
        return proxy;
    }
};
具体地说,我担心的是从
X::get\u proxy()
方法返回对象的部分。从技术上讲,谁调用move构造函数,将对象从方法体移动到临时对象,即该方法的返回值?标准是否说它是在X的范围内完成的,所以
friend
说明符在这里正确工作

它使用GCC 4.7-4.9和clang 3.0-3.5编译时既没有警告也没有错误。但我只需要第三方的确认,这在未来不会改变,因为这是一种标准化的行为

注意:这个代码示例可能看起来很傻,但它是一个精简的通用示例。在现实世界中,应用程序代理用于公开X的一些内部数据,而不是对X的引用


注意:这里我使用move构造函数,因为这是一个未来,是时候继续前进,忘记旧的标准了。但是这个代理可以用一个复制构造函数代替。尽管这并没有改变问题。除非在c++03和c++11/14之间,此范围内的情况发生了变化。

请考虑此常规函数定义:

struct T { /* ... */ };   // to be sure that "T" is an object type

T foo()
{
    T x(1, 2, 3);
    return x;
}
函数
foo
返回类型为
T
的PR值。现在函数求值
foo()
正式包含两个构造函数:首先构造
x
,然后构造返回值,返回值是从
x
复制或移动构造的(取决于类型
T
的详细信息)

最后,当您在其他地方将变量初始化为
ta=foo(),还有第三个正式构造函数调用,即从临时构造函数复制
a
。(复制省略允许省略两个复制构造函数,其效果可能就像您说的
ta(1,2,3);

在上述情况下,所有构造函数都必须在正式调用时可以访问。在我的简化示例和您的原始代码中,没有一个调用位于
T
的成员函数内,因此如果构造函数是
private
,那么调用站点需要是类的
朋友


你的代码看起来做得很正确。

@KerrekSB,是的,的确,谢谢你,现已修复。@KerrekSB,
std::set
无法工作,没有
operator@KerrekSB,请阅读我的评论。
std::vector
std::list
都不起作用。
X::Proxy
的移动构造函数是私有的:错误:“X::Proxy”类型的字段具有私有移动构造函数,您是对的。不要介意。泄漏的一种方法是
auto&&x=x()
,但是您可以通过左值限定
get\u proxy
成员来解决这个问题。@KerrekSB,是的,这是可以做到的。但是它是可以接受的,因为它不能将
Proxy
生存期扩展到调用
X::get_Proxy
的范围之外。你看,问题是我不确定,然后是返回值的构造,它是从X构造的复制或移动(取决于类型T的细节)从
foo()
的主体中正式调用,以及标准是否明确定义了它。