代码之家  ›  专栏  ›  技术社区  ›  Hanfei Sun

为矩形A=矩形(3,4);等价于矩形A(3,4);?

  •  1
  • Hanfei Sun  · 技术社区  · 7 年前

    以下是我的代码:

    #include <iostream>
    using namespace std;
    
    class Rectangle {
      int width, height;
     public:
      Rectangle(int, int);
      int area() { return (width * height); }
    };
    
    Rectangle::Rectangle(int a, int b) {
    
      width = a;
      height = b;
    }
    
    int main() {
      Rectangle A(3, 4);
      Rectangle B = Rectange(3,4);
      return 0;
    }
    

    Rectangle

    Rectangle B = Rectangle(3, 4); 实际上是连续做三件事?

    1. tmp 要表示它),请调用 Rectangle::Rectangle(3, 4)

    2. 为变量分配内存空间 B ,使用默认构造函数初始化它

    3. (memberwise)副本 tmp公司 B 使用赋值运算符 Rectangle& operator = (const Rectangle &)

    这个解释有意义吗?我想我可能理解错了,因为与其他方法相比,这个过程看起来非常笨拙和低效 Rectangle A(3, 4); .

    Rectangle A(3,4) 相当于 Rectangle A = Rectangle(3, 4); ? 谢谢

    4 回复  |  直到 7 年前
        1
  •  3
  •   Lightness Races in Orbit    7 年前

    是真的吗 Rectangle B = Rectangle(3, 4);

    不,那不是真的,但这真的不是你的错:这让人困惑。

    T obj2 = obj1 不是作业,而是 .

    你说得对 obj1 obj2 将使用 ,而不是默认构造然后分配给。


    对于 Rectangle C = new Rectangle(3, 4);

    不,它不会编译,但是 Rectangle* C

        2
  •  3
  •   Jerry Coffin    7 年前

    在这种情况下 发生了什么,理论上会发生什么。

    第一个很简单: Rectangle A(3, 4); 只需用 width height 初始化为 3 4 Rectangle(int, int); 您定义的构造函数。简单明了——因此,在可能的情况下,这是人们普遍喜欢和推荐的。

    那么让我们考虑一下: Rectangle B = Rectangle(3,4); 理论上,这会构造一个临时对象,然后复制构造 B

    实际上,编译器会检查 B 从那暂时的。经过检查,这是可能的,几乎任何有能力的编译器(至少在启用优化的情况下,甚至在没有启用优化的时候)都会生成与创建时基本相同的代码 A .

    但是,如果删除了复制构造函数,请添加:

    Rectangle(Rectangle const &) = delete;
    

    B 从临时开始,将拒绝编译代码。即使最终生成的代码实际上从未 复制构造函数,它必须可用才能工作。

    最后,让我们来看第三个示例(语法已更正):

    Rectangle *C = new Rectangle(3, 4);
    

    即使 有点像上面创建的线 B ,所涉及的构造实际上更像您以前创建的构造 只有 对象是(甚至理论上)创建的。它是从免费存储中分配的,并使用您的 构造函数。

    然后 用于初始化该对象的 C (这只是一个指针)。就像初始化 ,即使 Rectangle 长方形 卷入的

    Rectangle &operator=(Rectangle const &) = delete;
    

    = )代码中任何地方都没有赋值。

    要使用作业(如果你真的坚持这么做),你可以(例如)做以下事情:

    Rectangle A(3, 4);
    Rectangle B = Rectangle(5, 6);
    B = A;
    

    A. B A.

    = delete; 语法如上所示,但这不是唯一的一种。例如,如果类包含引用类型的成员变量,则编译器不会为您创建赋值运算符。如果你从这样简单的事情开始:

    struct Rectangle { 
        int width, height;
    };
    

    …编译器将完全自动生成默认构造函数、复制构造函数、移动构造函数、复制赋值和移动赋值运算符。

        3
  •  2
  •   Barry    7 年前

    Rectangle A(3, 4); 总是简单地调用 Rectangle(int, int)

    现在来看有趣的部分。

    Rectangle B = Rectangle(3,4); 立即塌陷为 Rectangle B(3,4); 这种情况的发生与 Rectangle 的move或copy构造函数是。此功能通常被称为保证复制省略,但需要强调的是,这里没有复制和移动。发生的是 B (3,4) .

    在C++17之前,有一个临时 长方形 构造为编译器可以优化(我的意思是,它肯定会优化,除非你告诉它不要优化)。但是你对事件的排序不正确。需要注意的是 这里没有作业 .我们不分配给 B .我们正在建设 B

    T var = expr;
    

    是副本-

    1. 我们建造了一个临时 长方形 使用 矩形(int,int)
    2. 该临时对象直接绑定到隐式生成的move(或copy,pre-C++11)构造函数中的引用,然后调用该构造函数-从临时对象执行成员级移动(或复制)。(或者,更准确地说,重载分辨率选择最佳的 长方形 长方形 )

    如果删除了移动构造函数(或C++11之前的版本),则会标记复制构造函数 private ),然后尝试构建 A 属于 B 一定会编译成相同的代码。


    B 如果您真的删除了类型,可能看起来更熟悉:

    auto B = Rectangle(3,4);
    

    Rectangle B = Rectangle(3, 4) ,只需第一步推导 B 长方形 .

        4
  •  -3
  •   Catau    7 年前
    1. Rectangle* C = new Rectangle(3,4);
    2. operator =(Rectangle& rho) 默认情况下定义为返回引用。因此 Rectangle B = Rectangle(3, 4); tmp