Asked  6 Months ago    Answers:  5   Viewed   28 times

Hi all I stumbled upon this piece of code today and I am confused as to what exactly happens and more particular in what order :

Code :

#include <iostream>

bool foo(double & m)
{
    m = 1.0;
    return true;
}

int main()
{
    double test = 0.0;
    std::cout << "Value of test is : t" << test << "tReturn value of function is : " << foo(test) <<  "tValue of test : " << test << std::endl;
    return 0;
}

The output is :

Value of test is :      1       Return value of function is : 1 Value of test : 0

Seeing this I would assume that somehow the right most argument is printed before the call to the function. So this is right to left evaluation?? During debugging though it seems that the function is called prior to the output which is what I would expect. I am using Win7 and MSVS 2010. Any help is appreciated!

 Answers

48

The evaluation order of elements in an expression is unspecified (except some very particular cases, such as the && and || operators and the ternary operator, which introduce sequence points); so, it's not guaranteed that test will be evaluated before or after foo(test) (which modifies it).

If your code relies on a particular order of evaluation the simplest method to obtain it is to split your expression in several separated statements.

Tuesday, June 1, 2021
 
TuomasR
answered 6 Months ago
62

The important part about order of evaluation is whether any of the components have side effects.

Suppose you have this:

int i = c() + a() * b();

Where a and b have side effects:

int global = 1;

int a() {
    return global++;
}
int b() {
    return ++global;
}
int c() {
    return global * 2;
}

The compiler can choose what order to call a(), b() and c() and then insert the results into the expression. At that point, precedence takes over and decides what order to apply the + and * operators.

In this example the most likely outcomes are either

  1. The compiler will evaluate c() first, followed by a() and then b(), resulting in i = 2 + 1 * 3 = 5
  2. The compiler will evaluate b() first, followed by a() and then c(), resulting in i = 6 + 2 * 2 = 10

But the compiler is free to choose whatever order it wants.

The short story is that precedence tells you the order in which operators are applied to arguments (* before +), whereas order of evaluation tells you in what order the arguments are resolved (a(), b(), c()). This is why they are "different but related".

Friday, July 30, 2021
 
nasty
answered 4 Months ago
74

It is definitely a bug in VS 2015.

In C++11, assigning temporary to const reference must not call copy constructor, but VS 2015 does.

You can check it with

#include <iostream>

struct Dummy
{
    Dummy() = default;
    Dummy(const Dummy &) { std::cout << "copy ctor" << std::endl; }
    void test() const { std::cout << "test" << std::endl; }
};  

int main()
{
    const Dummy& ref = Dummy();
    ref.test();
    return 0;
}

compiled on VS 2013, 2015, gcc and clang. Only VS (any version) calls copy constructor, if class constructor defined as = default.

I think VS compiiler still in 2015 erroneously uses old C++03 standard rules for this (8.5.3.5 of C++03):

If the initializer expression is an rvalue, with T2 a class type, and "cv1 T1" is reference-compatible with "cv2 T2," the reference is bound in one of the following ways (the choice is implementation-defined):

-- The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.

-- A temporary of type "cv1 T2" [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.

The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.

VS developers chose second way. They corrected this for empty user-defined constructor ({}), but forgot to do this for defaulted (= default) constructors.

PS. Bug on MS Connect (please vote)

Tuesday, September 14, 2021
 
jvf
answered 3 Months ago
jvf
68

This is a bug in GCC (thanks to Casey for the link). The paragraph you quoted applies in general to list initialization, where the terms are defined pretty clearly in paragraph 8.5.4/1:

List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list.

There is no reason to believe this should apply only to the invocation of an initializer list constructor. Also, the note in the paragraph you quoted clarifies that:

This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call.

Monday, October 18, 2021
 
Rod
answered 1 Month ago
Rod
92

1. Injection

You can inject your language extension to the scope of the parent scope by adding the following to your package.json:

"contributes": {
    "grammars": [
        {
            "scopeName": "source.asm.x86_64.your_syntax_extension",
            "path": "./syntaxes/your_syntax_extension.json",
            "injectTo": [ "source.asm.x86_64" ]
        }
    ]
}

2. Include

If your language extension uses a custom file-type or you want to override some of the parent scope's syntax definitions, you can write you own definition and include the parent scope. You can use either of the following formats:

your_syntax_extension.json

{
  "fileTypes": [
    "myExtension"
  ],
  "name": "Your Syntax Extension",
  "patterns": [
    {
      "include": "source.asm.x86_64"
    }
  ],
  "scopeName": "source.asm.x86_64.your_syntax_extension"
}

your_syntax_extension.tmLanguage

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>fileTypes</key>
    <array>
        <string>myExtension</string>
    </array>
    <key>name</key>
    <string>Your Syntax Extension</string>
    <key>patterns</key>
    <array>
        <dict>
            <key>include</key>
            <string>source.asm.x86_64</string>
        </dict>
    </array>
    <key>scopeName</key>
    <string>source.asm.x86_64.your_syntax_extension</string>
</dict>
</plist>

In both cases, you might want to include the extended package as a dependency. To do so, add its unique identifier to your package.json:

"extensionDependencies": [
    "13xforever.language-x86-64-assembly"
]
Monday, October 18, 2021
 
Conan
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share