由于C和C ++中的序列点,您遇到了哪些问题?
以下是由于序列点规则导致未定义行为的两个常见问题:
a[i] = i++; //has a read and write between sequence points i = i++; //2 writes between sequence points
您在序列点方面遇到的其他事情是什么?
当编译器无法警告我们时,很难找到这些问题。
达里奥的一个例子是:
void Foo(shared_ptr a, shared_ptr b){ ... } int main() { Foo(shared_ptr (new Bar), shared_ptr (new Bar)); }
这可能会泄漏内存。 在评估两个参数之间没有序列点,因此不仅可以在第一个参数之前评估第二个参数,而且还可以在任何shared_ptr
之前创建两个Bar对象。
也就是说,而不是被评估为
Bar* b0 = new Bar(); arg0 = shared_ptr(b0); Bar* b1 = new Bar(); arg1 = shared_ptr (b1); Foo(arg0, arg1);
(这将是安全的,因为如果成功分配b0
,它会立即包装在shared_ptr
),它可以被评估为:
Bar* b0 = new Bar(); Bar* b1 = new Bar(); arg0 = shared_ptr(b0); arg1 = shared_ptr (b1); Foo(arg0, arg1);
这意味着如果b0
成功分配,并且b1
抛出exception,则b0
永远不会被删除。
关于参数列表中的执行顺序或例如添加,存在一些不明确的情况。
#include using namespace std; int a() { cout << "Eval a" << endl; return 1; } int b() { cout << "Eval b" << endl; return 2; } int plus(int x, int y) { return x + y; } int main() { int x = a() + b(); int res = plus(a(), b()); return 0; }
首先执行()或b()吗? 😉
以下是Bjarne Stroustup使用c ++编写原则和实践的简单规则
“如果更改表达式中变量的值。不要在同一个表达式中读取或写入两次”
a[i] = i++; //i's value is changed once but read twice i = i++; //i's value is changed once but written twice
类似于Dario的一个例子,我也看到人们陷入其中:
printf("%s %s\n", inet_ntoa(&addr1), inet_ntoa(&addr2));
这不仅会打印“ addr1 addr1
”或“ addr2 addr2
”(因为inet_ntoa
返回指向静态缓冲区的指针,这些指针会被其他调用覆盖),但也没有定义它们中的哪一个(因为C没有指定)参数列表中的评估顺序)。
这里有两个适用于大多数C编译器的好表达式,但由于序列点而不明确:
x ^= y ^= x ^= y; // in-place swap of two variables
并且
int i=0; printf("%d %d %d", ++i, ++i, ++i); // usually prints out 3 2 1... but not for all compilers!
我最近看到的那个是由于程序员希望节省类格式化时间,完全是错误的:
class A { public: ... const char* Format( const string& f ) const { fmt = Print( f, value ); return fmt.c_str(); } operator const char* () const { return fmt.c_str(); } private: struct timeval value; mutable string fmt; }; A a( ... ); printf( "%s %s\n", a.Format( x ), a.Format( y );
class A { public: ... const char* Format( const string& f ) const { fmt = Print( f, value ); return fmt.c_str(); } operator const char* () const { return fmt.c_str(); } private: struct timeval value; mutable string fmt; }; A a( ... ); printf( "%s %s\n", a.Format( x ), a.Format( y );
最后一行要么总是为两种格式打印相同的值(要么使程序崩溃,因为内部字符串会释放返回的内存)。
另一个是我很久以前的一次采访:
void func( int x, int y, int z ) { printf( "%d %d %d\n", x, y, z ); } ... int i = 0; func( i, ++i, i++ ); /* don't do this in real software :) */