【问题标题】:Converting Constructor As The Return From A Function将构造函数转换为函数的返回值
【发布时间】:2013-10-05 16:35:38
【问题描述】:

即使没有 RVO 进化,是否可以使用转换构造函数而不是复制构造函数从函数返回对象(假设编译器不支持任何此类优化)?问题的关键是 C++ 标准告诉我什么,有人能告诉我吗?我得到了 gcc 并编译了下面的代码,在评论中也有几个问题。



    class A
    {
    public:
        A(int) {};
        A(int, int) {};

    private:
        A(const A &) = delete;
        A & operator = (const A &) = delete;
    };

    A foo(void)
    {// All the CEs below are all the same, which is 'using the deleted function 'A::A(const A&)''.
        //return(0); // Not compiled.
        //return(A(0)); // Not compiled. ok since the A isn't be copy-able.
        //return {0};  // Compiled. Is it a bug of the compiler?
        //return({0}); // Not compiled. What happened when returns in '()' implemented?
        //return 0;  // Not compiled. What happened when returns without '()' and '{}' implemented?
        //return ({0, 0}); // Not compiled.
        return {0, 0}; // Compiled. Realy??

    /*
      1. What are the differences in 'return 0', 'return {0}', 'return(0)' and 'return({0})'?
      2. Is it any possible to do conversion from source type object 'which is 'int' in this sample' to returning type of
    the function directly with only ONE constructor call even if the compiler has no any copying eliminating optimization
     but full compatibility with STD? Note that the function 'foo' here has no returning object accepter.
    */
    }

    int main(void)
    {
        foo(); // Note that there is no accepter of 'A' here, it's not discussing purpose at this topic of the post.
    }

    // compiling with the gcc ver. 4.8.1.

【问题讨论】:

    标签: c++ function constructor std rvo


    【解决方案1】:

    是的,如果您使用花括号初始化列表来初始化返回的对象,那么在返回语句中调用转换构造函数是完全有效的。

    C++11 标准在 6.6.3 [stmt.return] 中这样说:

    表达式的值被隐式转换为它出现的函数的返回类型。 return 语句可能涉及临时对象 (12.2) 的构造和复制或移动。 [注意: 为了重载决议 选择一个构造函数(12.8)。 — end note] 带有 braced-init-list 的 return 语句通过 copy-list-initialization (8.5.4) 初始化要从函数返回的对象或引用从指定的初始化列表。 [例子:

    std::pair<std::string,int> f(const char* p, int x) {
      return {p,x};
    }
    

    ——结束示例]

    在其他注释掉的 return 语句中,您创建一个临时对象,然后需要将其复制到返回的对象,这需要一个可访问的副本 ctor。

    【讨论】:

    • 谢谢,但我想问的是“如果复制构造函数和移动构造函数”都无法访问,比如私有或 = 删除,是否仍应允许编译代码?如果我在大括号之外实现括号,为什么编译器不会接受代码?似乎至少 gcc 会将代码示例中列出的返回视为不同的东西。
    • 好的,我现在了解对 RVO 的引用(注意,无论代码是否编译,RVO 都不会改变,如果需要复制构造函数,那么即使 RVO 发生也仍然需要它。)是的,代码是有效的, 就像我说的。我会更新答案。
    • 谢谢。我仍在寻找有关您提供的样本的答案。问题是如果'return {p, x};'将像 std::pair<:string>(p, x) 但被(由编译器)分析为 std::pair<:string>(std::pair<:>(p,x));
    • ,或者当使用括号初始化列表作为返回时,根本没有复制/rv-move 构造(即使没有进化 RVO)。如果答案是后者,那么一切都说得通,或者只是应该考虑的编译器的错误。
    • 后者,返回对象用花括号初始化列表初始化时没有复制/移动。
    猜你喜欢
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 2012-12-10
    相关资源
    最近更新 更多