C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] - نسخه متنی

Herb Sutter, Andrei Alexandrescu

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Discussion


The primary reason not to overload

operator&&, operator|| , or

operator, (comma) is that you

cannot implement the full semantics of the built-in operators in these three cases, and programmers commonly expect those semantics. In particular, the built-in versions evaluate left-to-right, and for

&& and

|| also use short-circuit evaluation.

The built-in versions of

&& and

|| first evaluate their left-hand expression, and if that fully determines the result (

false for

&&, true for

|| ) then the right-hand expression doesn't need to be evaluatedand is guaranteed not to be. We all get so used to this handy feature that we routinely allow the correctness of the right-hand side depend on the success of the left-hand side:

Employee* e = TryToGetEmployee();
if(

e && e->Manager() )

// …

This code's correctness relies on the fact that

e->Manager() will not be evaluated if

e is null. This is perfectly usual and fineunless the

&& used is an overloaded

operator&& , because then the expression involving

&& will follow function rules instead:

  • Function calls always evaluate

    all arguments before execution.

  • The

    order of evaluation of function arguments is unspecified. (See also Item 31.)


So let's look at a modernized version of the snippet above that uses smart pointers:

some_smart_ptr< Employee

> e = TryToGetEmployee();
if(

e && e->Manager() )

// …

Now, say this code happens to invoke an overloaded

operator&& (provided by the author either of

some_smart_ptr or of

Employee ). Then the code will still look fine to the reader, but will potentially (and disastrously) call

e->Manager() when

e is null.

Some other code won't dump core even in the presence of such eager evaluation, but becomes incorrect for a different reason if it depends on the order in which the two expressions are evaluated. The effects, of course, can be just as harmful. Consider:

if(

DisplayPrompt() && GetLine() )

// …

If

operator&& is a user-defined operator, it is unspecified whether

DisplayPrompt or

GetLine is called first. The program could inadvertently end up waiting for input from the user before displaying the explanatory prompt.

Of course, such code may seem to work with your current compiler and build settings. It's still fragile. Compilers can (and do) choose whatever order they find fit best for any particular call, taking into account concerns such as generated code size, available registers, expression complexity, and so on. So the same call might behave differently depending on the compiler version, the compiler switch settings, and even on the statements surrounding the call.

The same fragility occurs with the comma operator. Like

&& and

|| , the built-in comma guarantees that its expressions will be evaluated left-to-right (unlike

&& and

|| , it always evaluates both). A user-defined comma operator cannot guarantee left-to-right evaluation, usually with surprising results. For example, if the following code invokes a user-defined comma operator, it is unspecified which of

f or

g receives the value

0 and which receives the value

1 .

int i = 0;
f( i++ ), g( i++ );

// see also Item 31


/ 521