C++返回值为对象时复制构造函数不执行怎么破

简介:   先说点背景知识,调用复制构造函数的三种情况:  1.当用类一个对象去初始化另一个对象时。  2.如果函数形参是类对象。  3.如果函数返回值是类对象,函数执行完成返回调用时。  在辅导学生上机时,有同学第3点提出异议。有教材上的例题为证:#include <iostream>using namespace std;class Point //Point

  先说点背景知识,调用复制构造函数的三种情况:

  1.当用类一个对象去初始化另一个对象时。

  2.如果函数形参是类对象。

  3.如果函数返回值是类对象,函数执行完成返回调用时。

  在辅导学生上机时,有同学第3点提出异议。有教材上的例题为证:

#include <iostream>
using namespace std;
class Point     //Point 类的定义
{
public:
    Point(int xx=0, int yy=0)
    {
        x = xx;    //构造函数,内联
        y = yy;
    }
    Point(const Point& p); //复制构造函数
    void setX(int xx)
    {
        x=xx;
    }
    void setY(int yy)
    {
        y=yy;
    }
    int getX() const
    {
        return x;    //常函数(第5章)
    }
    int getY() const
    {
        return y;    //常函数(第5章)
    }
private:
    int x, y; //私有数据
};
//成员函数的实现
Point::Point (const Point& p)
{
    x = p.x;
    y = p.y;
    cout << "Calling the copy constructor " << endl;
}

//形参为Point类对象的函数
void fun1(Point p)
{
    cout << p.getX() << endl;
}
//返回值为Point类对象的函数
Point fun2()
{
    Point a(1, 2);
    return a;
}

//主程序
int main()
{
    Point a(4, 5);	//第一个对象A
    Point b = a;	//情况一,用A初始化B。第一次调用复制构造函数
    cout << b.getX() << endl;
    fun1(b);	//情况二,对象B作为fun1的实参。第二次调用复制构造函数
    b = fun2();	//情况三,函数的返回值是类对象,函数返回时调用复制构造函数
    cout << b.getX() << endl;
    return 0;
}
  证据是,在CodeBlocks中,运行结果是:

  

  而不是期望的:
  

  显然,第3种情况下,复制构造函数没有被执行。

  确定问题后,我知道道理是对的,看过的几本书,厚的、薄的,都是这么写的。会不会是编译器的差别?CodeBlocks用的是gcc。gcc开源,跟标准的变化跟得紧,莫不是第3种情况已经成了老黄历,而各种书来不及变?

  我让她到VC++6.0中运行。一会儿她的反馈,在VC++6.0中复制构造函数执行了。

  真相明白了。

  这个问题需要有个交待。

  回家后再翻各种书,无果。网络搜索,CSDN上有个贴子《函数返回值是对象,是调用了拷贝构造函数?》,其中大家给的结论,是gcc做了优化,返回值为对象时,不再产生临时对象,因而不再调用复制构造函数。

  看来不是标准发生变化。

  那如果一定想要让这个构造函数执行呢?只需让忽略gcc不要搞这个优化就行了。贴子中给了个线索,在新浪博客《命名返回值优化》。文章称通过搜索知道“这是一个称为命名返回值优化的问题,而且g++的这个编译优化竟然没有直接的关闭方法给出解决办法”。作者是用命令行工作的,他后来解决的办法,是在编译命令中加上“-fno-elide-constructors”参数,例g++ -fno-elide-constructors testReturn.cpp 。

  我的学生还处在用IDE的阶段。本文的价值来了,如何在CodeBlocks下也忽略这个优化项呢?

  在CodeBlocks中,通过菜单依次选:settings->Compiler...,在Global compiler settings部分,选择Other options,在文本框中写入“-fno-elide-constructors”,如图,然后就可以ok啦。

  

  然后,如同苦难的公主终于和王子过上了幸福的生活一样,期望的结果有了。

  

  “-fno-elide-constructors”选项起了作用,有图为证。下面中加上这个参数后,编译完看到的提示信息:

  

目录
相关文章
|
2月前
|
编译器 C++
C++之类与对象(完结撒花篇)(上)
C++之类与对象(完结撒花篇)(上)
40 0
|
29天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
80 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
86 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
31 4
|
2月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
31 4
|
2月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
18 0
|
2月前
|
编译器 C++ 数据库管理
C++之类与对象(完结撒花篇)(下)
C++之类与对象(完结撒花篇)(下)
36 0
|
2月前
|
编译器 C++
C++之类与对象(3)(下)
C++之类与对象(3)(下)
36 0
|
23天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
38 2