Posts Tagged ‘C++0x’

Integer division

C89 and C++98 say the result of an integer division where the divisor and/or dividend is negative is implementation defined. This reflects that early hardware implemented integer divisions differently.

According to C89/C++98, we may have either (-3)/2 == -1 (round toward zero) or (-3)/2 == -2 (round toward negative infinity).

It appears round toward zero has become the overwhelming de facto standard now, adopted by both hardware and software vendors. Now both C and C++ explicitly require round toward zero in their new standards (C99 and C++2011*).

Division of negative integers has always been a complicated problem. Fortran mandated the same round-toward-zero mode much earlier than C/C++; so did Java. Python, on the other hand, has required round toward -∞ (i.e. (-3)//2 == -2) from its beginning. Everybody, nevertheless, agrees that a/b*b + a%b == a should always hold.

* C++0x has yet to be officially approved. Hopefully it will be approved within this year and known as C++2011. I’m using this name prematurely.

Tags: , ,

An Rvalue Reference Issue

I’m now convinced it was way too premature to try to take advantage of C++0x features (r-value references, etc.) in tiary (if the compiler supports).

With GCC 4.3.4, even the following innocent function leads to segmentation fault:

#include <string>
#include <utility>

std::string && my_move (std::string &str)
{
    std::string && tmp = std::move (str);
    return tmp;
}

In GCC 4.4, this function simply casts the non-const lvalue-reference parameter to an r-value reference and returns it, which I think is correct. In 4.3, however, tmp refers to a temporary object on stack, move-constructed from str.

Then I replaced std::string with std::list<int> and tried again. This time, GCC (4.3.4) itself segfaults. Ooops..

Tags: , , ,

std::hash<std::string>

TR1 requires std::tr1::hash (std::hash in C++0x) to be instantiable for integer/floating point types, std::string and std::wstring. (C++0x added std::error_code, std::thread:id, std::bitset, std::u16string, std::u32string, and std::vector<bool>.)

But for strings, every call to std::hash<string>::operator()(std::string) incurs an unnecessary copy construction, which can be expensive in implementations where std::basic_string does not use COW.

Developers of GCC are apparently aware of this, and they added specializations std::hash<const std::string &> and std::hash<const std::wstring &> starting from GCC 4.3.

However, I still guess we cannot easily benefit from this since we will need to write something like this:

std::unordered_set<std::string, std::hash<const std::string &>>

(In C++0x it’s no longer required to insert a space between the two larger-than characters.)

Too ugly and inconvenient to use, unless our program is really time critical.

Tags: , , ,

Rvalue reference

The new feature in C++0x was rather confusing to me until yesterday when I suddenly realized that my codes could be more efficient if we had rvalue references.

In my understanding, the main practical use of rvalue references is to eliminate spurious copies by introducing a “move” semantics in addition to the existing “copy” semantics.

Suppose we have a map object: map<int,SomeComplexType> my_map;

The most intuitive statement to add something to it is my_map[key] = value;.

In current C++, a copy assignment must be triggered here, potentially unnecessary and expensive. (“Copy” semantics.)

If value will not be used later (esp. it’s a temporary object), we may want to “move” instead of “copy” it into the map. (“Move” semantics.)
[Sure, we can use value.swap (my_map[key]); if swapping is efficient (e.g. STL strings & containers). But this is rather unreadable.]

In C++0x, with rvalue references, we can distinguish them easily:

  1. Use "copy" semantics in SomeComplexType::operator = (const SomeComplexType &);
  2. Use "move" semantics in SomeComplexType::operator = (SomeComplexType &&); (Should we call it a "move assignment"?)

Now the compiler automatically chooses between the "copy" or "move" semantics for my_map[key] = value;, depending on whether value is an rvalue or not.

It is also possible to force the "move" semantics: my_map[key] = std::move (value);

What std::move does is accept either an lvalue or rvalue reference, and return it as an rvalue reference.


Microsoft Visual C++ supports, as a non-standard extension, binding temporary objects to non-const (lvalue) references. This extension cannot substitute rvalue references:

string a = "Hello";
string b = a;

If we use move semantics in string::string (string &), then a will be empty after b's construction. This usually is not what we desire.


Again, my main concern about C++0x is that it's going to be too complicated to learn.


Reference:
A Brief Introduction to Rvalue References

Tags: ,

C++0x in ICC 11

Intel is advancing faster than GNU in support the upcoming C++0x. The two features I expect most, auto declaration and lambda function, have both been supported satisfactorily. Lambda functions that use variables defined outside (output_and_sum in the following demo) are supported as well as simpler ones (add in the following demo).

#include <cstdio>
#include <algorithm>
using namespace std;
 
int main()
{
    static const int myvec[] = { 1, 2, 3, 4, 5 };
 
    int sum = 0;
    auto add = [] (int a, int b) -> int { return a+b; };
    auto output_and_sum = [&sum,add](int x) { sum  = add(sum,x); printf ("%d\n", x); };
    for_each (myvec, myvec+5, output_and_sum);
    printf ("sum = %d\n", sum);
}

(I use printf instead of cout merely to make the assembly list more readable.)

ICC compiles this program (an option -std=c++0x is necessary, of course) and gives the correct resuls:

1
2
3
4
5
sum = 15

Also the two lambda functions are well inlined and optimized – variable sum, which is used by the lambda function by reference, is completely stored in a register, though it is easy to find several useless instructions in the assembly dump.

Some other less important (in my view) features (e.g. initializer_list) are not implemented yet. (BTW, I really had a hard time finding the “request noncommercial free license” link on Intel’s website, while I could see the link to “buy a commercial license” everywhere..)

Hopefully C++0x will be more successful than C99, which is filled with ugly and nobody-wants-to-implement features.

Tags: , ,

C++0x draft finished

Only bugfixes, no new feature, will be added to the standard from now on.

Good. It is almost certain it will be called C++ 2009.

As I see, many new features will bring great convenience to programming. But… C++ will appear far more complicated and difficult and perhaps unreasonable to a newbie. It’s already complicated enough now…

Ten years ago C9x became C99, and now C++0x is becoming C++09. But there will be one certain difference: No major compiler completely implements C99 even today; however, every actively developed C++ compiler seems to be planning to add C++09 support as immediately as possible.

Reference
[1] September 2008 ISO C++ Standards Meeting: The Draft Has Landed, and a New Convener

Tags: ,