c++ primer 4.1.3节练习答案

练习4.3

个人表示可以接受,贴一段别人对于这个问题的理解,原帖地址:http://blog.csdn.net/wmaoshu/article/details/50115721

表达式的意义:

1)定义了表达式计算过程(运算符的优先级 和结合律 运算对象的求值顺序)

2)指出对环境(可以把环境看作当时可用的所有变量)是否有影响。即有否有副作用。

程序潜在缺陷是怎么产生的?也就是,如果 C/C++  程序里的某个表达式(部分)有副作用,这种副作用何时才能实际体现到使用中?

程序执行中存在一系列顺序点(时刻),语言保证一旦执行到达一个顺序点,在此之前发生的所有修改(副作用)都必须实现(必须反应到随后对同一存储位置的访问中) ,在此之后的所有修改都还没有发生。在顺序点之间则没有任何保证。对 C/C++ 语言这类允许表达式有副作用的语言,顺序点的概念特别重要。

C/C++语言定义(语言的参考手册)明确定义了顺序点的概念。顺序点位于:

1.  每个完整表达式结束时。完整表达式包括变量初始化表达式,表达式语句,return 语句的表达式,以及条件、循环和 switch 语句的控制表达式(for 头部有三个控制表达式);

2.  运算符 &&、||、?:  和逗号运算符的第一个运算对象计算之后;

3.  函数调用中对所有实际参数和函数名表达式(需要调用的函数也可能通过表达式描述)的求值完成之后(进入函数体之前)。

所以在 上一个顺序点 到下一个顺序点之间,所有的副作用都要实现,但实现的顺序就不一定了。

例如:

a = 1;

fun(a++, b, a+5);

Fun函数的调用表达式就位于a=1;完成的顺序点之后 在这个函数调用的顺序点之前。在这之间 要执行 a++ , b , a+5 这几个表达式,但是其中a++有副作用,但是这个副作用在a+5之后实现 还是在之前实现,是未定义的。

问题回答:

C/C++ 语言的做法完全是有意而为,其目的就是允许编译器采用任何求值顺序,使编译器在优化中可以根据需要调整实现表达式求值的指令序列,以得到效率更高的代码。像 Java 那样严格规定表达式的求值顺序和效果,不仅限制了语言的实现方式,还要求更频繁的内存访问(以实现副作用),这些可能带来可观的效率损失。应该说,在这个问题上,C/C++和 Java 的选择都贯彻了它们各自的设计原则,各有所获(C/C++  潜在的效率,Java 更清晰的程序行为),当然也都有所失。还应该指出,大部分程序设计语言实际上都采用了类似 C/C++的规定。

C/C++  语言的规定告诉我们,任何依赖于特定计算顺序、依赖于在顺序点之间实现修改效果的表达式,其结果都没有保证。程序设计中应该贯彻的规则是:如果在任何“完整表达式”(形成一段由顺序点结束的计算)里存在对同一“变量”的多个引用,那么表达式里就不应该出现对这一“变量”的副作用。否则就不能保证得到预期结果。

时间: 2024-08-29 10:06:20

c++ primer 4.1.3节练习答案的相关文章

c++ primer 6.5.1节练习答案

练习6.40 a)正确 b)错误,一旦某个形参被赋予了默认值,他后面的所有形参都必须有默认值. 练习6.41 a)错误,ht没有默认实参,而a的实参列表里也没有给出实参: b)合法,调用init(24 ,10 ,' '): c)虽然合法,但是与程序猿的设计初衷不符,*会转换成十进制的数43,相当于调用init(14, 43, ' '): 练习6.42 1 string make_plural(size_t ctr, const string &word, const string &end

c++ primer 5.1.1节练习答案

练习5.20 1 int main() 2 { 3 vector<string> str; 4 string str1; 5 while (cin >> str1) 6 { 7 auto last = str.end(); 8 if (str.size() != 0 && str1 == (*(last-1))) 9 { 10 cout << str1 << endl; 11 break; 12 } 13 else 14 str.push_b

c++ primer 5.5.3节练习答案

练习5.22 1 int main() 2 { 3 int sz = get_size(); 4 while (sz <= 0) 5 { 6 sz = get_size(); 7 continue; 8 } 9 system("pause"); 10 return 0; 11 }

c++ primer 5.5.2节练习答案

练习5.21 1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 int main() 7 { 8 vector<string> str; 9 string str1; 10 while (cin >> str1) 11 { 12 auto last = str.end()

c++ primer 6.5.2节练习答案

练习6.43 a)放在头文件,因为内联函数和constexpr函数一般写在头文件中 b)函数的定义一般写在源文件,而声明放在头文件 练习6.44 1 inline bool isShorter(const string &s1, const string &s2) 2 { 3 return s1.size() < s2.size(); 4 } 练习6.45 内联函数一般用于优化规模小.流程直接.频繁调用的函数. 练习6.46 不行,isShorter函数如果定义成constexpr函

c++ primer 5.4.4节练习答案

练习5.18 a)循环体少了花括号: b)不允许在条件部分定义变量: c)condition使用的变量必须定义在循环体之外: 练习5.19 1 int main() 2 { 3 string str1, str2; 4 int i; 5 do 6 { 7 cout << "please enter two string:"; 8 if (cin >> str1 >> str2) 9 { 10 if (str1.size() < str2.siz

c++ primer 6.2.4节练习答案

练习6.21 1 int max(const int x, const int *y) 2 { 3 if (x > *y) 4 return x; 5 else 6 return *y; 7 } 8 9 int main() 10 { 11 int a1, a2; 12 while (cin >> a1 >> a2) 13 { 14 cout << "the max is " << max(a1, &a2) <<

c++ primer 6.2.3节练习答案

练习6.16 1 bool is_empty(const string &s) { return s.empty(); } 练习6.17 1 bool have_upper(const string &s) 2 { 3 for (auto c : s) 4 { 5 if (isupper(c)) 6 return true; 7 } 8 return false; 9 } 10 11 void to_lower(string &s) 12 { 13 for (auto &c

c++ primer 5.4.1节练习答案

练习5.14 1 int main() 2 { 3 vector<string> str; 4 string str1,str2; 5 int max = 0; 6 while (cin >> str1) 7 { 8 int cnt = 0; 9 str.push_back(str1); 10 auto it = str.begin(); 11 while (it != str.end()) 12 { 13 if (*it == str1) 14 ++cnt; 15 ++it; 1

c++ primer 4.11.1节练习答案

练习4.34 a) float->bool b) int->float->double c) char->int->double 练习4.35 a) char->int->char b) int->unsigned int->float c) float->unsigned int->double d) int->float->double->char