当前位置: 首页> 科技> 数码 > 《More Effective C++》《效率——19、了解临时对象的来源》

《More Effective C++》《效率——19、了解临时对象的来源》

时间:2025/7/9 11:56:31来源:https://blog.csdn.net/zwh1298454060/article/details/140579601 浏览次数:0次

文章目录

  • 1、Terms19:了解临时对象的来源
    • 1.1 为了使函数调用成功而进行隐式类型转换的时候
    • 1.2 当函数返回对象的时候。
    • 1.3 补充说明
  • 2、总结
  • 3、参考

1、Terms19:了解临时对象的来源

什么是临时对象?

C++真正的临时对象是不可见的匿名对象,不会出现在你的源码中,但是程序在运行时确实生成了这样的对象。

通常出现在以下两种情况:

1.1 为了使函数调用成功而进行隐式类型转换的时候

传递某对象给一个函数,而其类型与函数的形参类型不同时,如果可以通过隐式转化的话可以使函数调用成功,那么此时会通过构造函数生成一个临时对象,当函数返回时临时对象即自动销毁。如下例:

//计算字符ch在字符串str中出现的次数
int countChar (const string& str, char ch);
char buffer[];
char c;
//调用上面的函数
countChar (buffer, c);

我们看的第一个参数为char[],而函数的参数类型为const string&,参数不一致,看看能否进行隐式转化,string类有个构造函数是可以作为隐式转化函数的。那么编译器会产生一个string的临时变量,以buffer为参数进行构造,那么countChar中的str参数会绑定到此临时变量上,直到函数返回时销毁。
注意这样的转化只会出现在两种情况下:函数参数以传值(by value)的方式传递 或者 对象被传递到一个 reference-to-const 参数上。

传值方式:
int countChar (string str, char ch);
string buffer;
char c;
//参数通过传值方式传递
countChar (buffer, c);

这种方法会调用string的拷贝构造函数生成一个临时变量,再将这个临时变量绑定到str上,函数返回时进行销毁。

传常量引用:
开始的实例即时属于这种情况,但一定强调的是传递的是const型引用,如将开始函数的原型改为

int countChar (string& str, char ch);

下面调用相同,编译器会报错!为什么C++设计时要求 当对象传递给一个reference-to-non-const 参数不会发生隐式类型转化呢?

下面的实例可能向你说明这样设计的目的:

//声明一个将str中字符全部转化为大写
void toUpper (string& str);
char buffer[] = "hazirguo";
toUpper(buffer);                 //error!!非const引用传递参数不能完成隐式转化

如果编译器允许上面的传递完成,那么,会生成一个临时对象,toUpper函数将临时变量的字符转化为大写,返回是销毁对象,但是对buffer内容毫无影响!程序设计的目地是期望对“非临时对象”进行修改,而如果对reference-to-non-cosnt对象进行转化,函数只会对临时变量进行修改。这就是为什么C++中要禁止non-const-reference参数产生临时变量的原因了。

1.2 当函数返回对象的时候。

当函数返回一个对象时,编译器会生成一个临时对象返回,如声明一个函数用来合并两个字符串:

const string strMerge (const string s1, const string s2);

大多时候是无法避免这样的临时变量产生的,但是现代编译器可以将这样的临时变量进行优化掉,这样的优化策略中,有个所谓的“返回值优化”。

1.3 补充说明

1、为什么C++语言禁止为 non-const rference参数产生临时对象
在C++中,禁止为non-const reference参数产生临时对象的主要原因涉及到语言的设计原则、效率和语义清晰性。下面详细解释这几点:

  1. 设计原则
    C++的设计哲学之一是提供对底层资源的直接控制,同时保持语言的高效性。允许为non-const reference参数产生临时对象会违背这一原则,因为它会引入额外的、可能不必要的临时对象创建和销毁开销。

  2. 效率
    如果允许为non-const reference参数产生临时对象,那么每次调用这样的函数时,都会创建一个临时对象,并将其地址传递给函数。这不仅会增加额外的内存分配和释放开销,还可能引入额外的拷贝或移动操作。这对于性能敏感的应用程序来说是不可接受的。

  3. 语义清晰性
    在C++中,引用通常用于表示对某个已存在对象的直接访问。如果允许为non-const reference参数产生临时对象,那么这种直接访问的语义就会变得模糊。程序员可能很难理解函数是在修改一个已存在的对象,还是在修改一个临时的、即将被销毁的对象的副本。

  4. 避免意外修改
    如果允许non-const reference参数接受临时对象,那么函数内部对引用的修改实际上会作用于一个临时对象上,而不是调用者期望的那个对象。这可能会导致程序行为的不一致和难以追踪的错误。

综上所述,C++禁止为non-const reference参数产生临时对象是为了保持语言的高效性、设计原则的一致性和语义的清晰性。如果函数需要接受一个可能不存在的对象,那么应该使用指针或者const reference作为参数类型,并在函数内部进行相应的空指针检查或只读操作。
2、为什么说看到一个reference-to-const参数,极有可能产生一个临时对象绑定至该参数上
实际上,看到一个reference-to-const参数时,并不意味着“极可能”一个临时对象会绑定到该参数上。相反,reference-to-const的设计初衷是为了避免临时对象的创建,因为它允许函数直接引用传入的实参,而无需进行拷贝。

然而,在某些特定情况下,确实可能会有临时对象绑定到reference-to-const参数上。这通常发生在需要类型转换,且转换的结果是一个临时对象时。下面是一个例子:

#include <iostream>class Base {
public:virtual ~Base() {}virtual void print() const { std::cout << "Base" << std::endl; }
};class Derived : public Base {
public:void print() const override { std::cout << "Derived" << std::endl; }
};void printConstRef(const Base& obj) {obj.print();
}int main() {Derived derived;printConstRef(derived); // 这里没有临时对象,直接引用derived// 下面的调用会导致创建一个Base类型的临时对象printConstRef(Derived()); // 这里创建了一个Derived类型的临时对象,并将其转换为Base类型的临时对象return 0;
}

在这个例子中,printConstRef函数接受一个const Base&类型的参数,即一个指向Base类型的常量引用。在main函数中,我们首先传递了一个Derived类型的对象derived给这个函数,这里没有创建临时对象,因为derived可以直接被引用。

然而,在printConstRef(Derived())的调用中,我们传递了一个Derived类型的临时对象。由于printConstRef函数接受的是Base类型的引用,因此会创建一个Base类型的临时对象来表示这个Derived类型的临时对象,并将这个Base类型的临时对象传递给printConstRef函数。这里确实有一个临时对象被创建并绑定到了reference-to-const参数上。

但是,这种情况并不是reference-to-const参数的常见用法,也不是设计者的初衷。通常,我们会尽量避免在需要传递临时对象给reference-to-const参数的函数调用中创建临时对象,以提高代码的效率。

2、总结

(1)临时对象有构造和析构的成本,影响程序的效率,因此尽可能地消除它们;
(2)更为重要的是很快地发现什么地方会生成临时对象:
(3)当我们看到一个reference-to-const参数时,极可能一个临时对象绑定到该参数上;
(4)当我们看到函数返回一个对象时,就会产生临时对象。

3、参考

《More Effective C++》

关键字:《More Effective C++》《效率——19、了解临时对象的来源》

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: