为了账号安全,请及时绑定邮箱和手机立即绑定

C+程序员应该知道哪些常见的未定义行为?

C+程序员应该知道哪些常见的未定义行为?

C C++
holdtom 2019-05-30 17:40:44
C+程序员应该知道哪些常见的未定义行为?C+程序员应该知道哪些常见的未定义行为?比如说:a[i] = i++;
查看完整描述

3 回答

?
不负相思意

TA贡献1777条经验 获得超10个赞

计算函数参数的顺序是未指定行为。(这不会使你的节目崩溃,爆炸,或订购比萨饼.不像未定行为.)

唯一的要求是在调用函数之前必须对所有参数进行完全评估。


这是:

// The simple obvious one.callFunc(getA(),getB());

可以等效于以下内容:

int a = getA();int b = getB();callFunc(a,b);

或者这个:

int b = getB();int a = getA();callFunc(a,b);

这两者都可以;这取决于编译器。结果可能很重要,取决于副作用。


查看完整回答
反对 回复 2019-05-30
?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞


编译器可以自由地重新排序表达式的计算部分(假设含义不变)。


根据原来的问题:


a[i] = i++;


// This expression has three parts:

(a) a[i]

(b) i++

(c) Assign (b) to (a)


// (c) is guaranteed to happen after (a) and (b)

// But (a) and (b) can be done in either order.

// See n2521 Section 5.17

// (b) increments i but returns the original value.

// See n2521 Section 5.2.6

// Thus this expression can be written as:


int rhs  = i++;

int lhs& = a[i];

lhs = rhs;


// or

int lhs& = a[i];

int rhs  = i++;

lhs = rhs;

双重检查锁定。一个容易犯的错误。


A* a = new A("plop");


// Looks simple enough.

// But this can be split into three parts.

(a) allocate Memory

(b) Call constructor

(c) Assign value to 'a'


// No problem here:

// The compiler is allowed to do this:

(a) allocate Memory

(c) Assign value to 'a'

(b) Call constructor.

// This is because the whole thing is between two sequence points.


// So what is the big deal.

// Simple Double checked lock. (I know there are many other problems with this).

if (a == null) // (Point B)

{

    Lock   lock(mutex);

    if (a == null)

    {

        a = new A("Plop");  // (Point A).

    }

}

a->doStuff();


// Think of this situation.

// Thread 1: Reaches point A. Executes (a)(c)

// Thread 1: Is about to do (b) and gets unscheduled.

// Thread 2: Reaches point B. It can now skip the if block

//           Remember (c) has been done thus 'a' is not NULL.

//           But the memory has not been initialized.

//           Thread 2 now executes doStuff() on an uninitialized variable.


// The solution to this problem is to move the assignment of 'a'

// To the other side of the sequence point.

if (a == null) // (Point B)

{

    Lock   lock(mutex);

    if (a == null)

    {

        A* tmp = new A("Plop");  // (Point A).

        a = tmp;

    }

}

a->doStuff();


// Of course there are still other problems because of C++ support for

// threads. But hopefully these are addresses in the next standard.


查看完整回答
反对 回复 2019-05-30
  • 3 回答
  • 0 关注
  • 648 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信