繁体   English   中英

立即定义带有值的字符串时建议的速度提升,而不是延迟

[英]Suggested speed improvement when defining string with value immediately, instead of delaying

我目前正在阅读Bjarne Stroustrup撰写的“The C ++ Programming Language:Special Edition”和第133页,其中说明如下:

对于用户定义的类型,将变量的定义推迟到合适的初始化程序可用之后,也可以获得更好的性能。 例如:

 string s; /* .... */ s = "The best is the enemy of the good."; 

很容易慢得多

 string s = "Voltaire"; 

我知道状态很容易 ,这意味着它不一定是这样,但是我们只是说它确实发生了。

为什么这会带来潜在的性能提升?

它只是用户定义的类型(甚至是STL类型),还是intfloat等的情况呢?

我会说这主要是关于具有非平凡默认构造函数的类型,至少就性能而言。

两种方法的区别在于:

  • 在第一个版本中,首先构造一个空字符串(使用默认构造函数); 然后赋值运算符用于有效地丢弃默认构造函数完成的工作,并将新值赋给字符串。
  • 在第二个版本中,在构造点立即设置所需的值。

当然,事先告诉我们这会产生多大的性能差异真的很难。

  1. 执行默认构造函数需要时间。 覆盖它在随后调用的赋值运算符中初始化字符串的内容也需要时间。

  2. 当函数(由于return语句或异常)在默认构造函数和赋值运算符的调用之间留下时,执行可能永远不会到达赋值。 在这种情况下,对象被不必要地默认初始化

  3. 实现可能会浪费性能以确保在抛出异常时调用对象析构函数 如果在后续范围内初始化对象,则从未达到该范围,也不需要。

因为:

string s;  /* .... */ s = "The best is the enemy of the good.";    

涉及两个操作:构造和分配

而:

string s = "Voltaire";   

仅涉及施工。

这相当于在构造函数体中的Assignment上选择Member Initializer列表

这是个好问题。 你是对的,这只发生在复杂的类型中。 即类和结构,std :: string就是这样一个对象。 这里涉及的真正问题与构造函数有关。

创建对象时,即

std::string s;

它的构造函数被调用,它可能会分配一些内存,做一些其他的变量初始化,让它自己准备好使用。 实际上,代码中此时可以执行大量代码。

稍后你会做:

s = "hello world!";

这导致类必须抛弃它所做的大部分工作,并准备用新字符串替换它的内容。

如果在定义变量时设置值,则实际上减少为单个操作,即:

std::string s = "Hello world";

事实上,如果您在调试器中查看代码,请执行一次不同的构造函数,而不是构造对象,然后单独设置一个值。 实际上,之前的代码与以下代码相同:

std::string s("Hello world");

我希望这有助于澄清一些事情。

考虑两种情况都会发生什么。 在第一种情况下:

  • 默认构造函数调用“s”
  • 赋值运算符调用“s”

在第二种情况下,首先考虑使用copy elision,这相当于string s("Voltaire") ,因此:

  • c-string构造函数调用

逻辑上,第一种方法需要抽象机器做更多的工作。 这实际上是否转换为更实际的代码取决于实际类型以及优化器可以执行的操作。 虽然请注意,对于除了普通用户类型以外的所有用户类型,优化器可能必须假设默认构造函数具有副作用,因此不能简单地将其删除。

此额外成本应仅适用于用户类型,因为成本在默认构造函数中。 对于像int这样的任何原始类型,或者实际上任何具有普通构造函数/副本的原始类型,默认构造函数都没有成本 - 数据根本不会被初始化(在函数范围内)。

为什么这会带来潜在的性能提升?

第一种情况涉及默认初始化,然后是分配; 第二个涉及从价值初始化。 默认初始化可能会做一些以后必须通过赋值重做(甚至撤消)的工作,因此第一种情况可能涉及比第二种情况更多的工作。

它只是用户定义的类型(甚至是STL类型),还是int,float等的情况呢?

只有用户定义的类型才是这样; 然后它取决于构造函数和赋值运算符实际执行的操作。 对于标量类型,默认初始化不执行任何操作,并且赋值与从值初始化完成相同的操作,因此两个备选方案都是等效的。

该类有三种方法来初始化字符串:

string  s;         // Default constructor
string  s = "..."; // Default constructor followed by operator assignment
string  s("...");  // Constructor with parameters passed in

字符串类需要分配内存。 一旦知道需要多少内存,最好分配它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM