13 Apr 2014, tagged: #Cpp

Bjarne Stroustrup’s FAQ

Bjarne Stroustrup’s FAQ

Bjarne Stroustrup’s C++ Style and Technique FAQ

C++11 FAQ

  • don’t use casts
  • keep arrays out of interfaces (hide them in the innards of high-performance functions and classes where they are needed and write the rest of the program using proper strings, vectors, etc.)
  • avoid void* (keep them inside low-level functions and data structures if you really need them and present type safe interfaces, usually templates, to your users)
  • avoid unions
  • if you have any doubts about the validity of a pointer, use a smart pointer instead,
  • don’t use “naked” new and delete (use containers, resource handles, etc., instead)
  • don’t use …-style variadic functions (“printf style”)
  • Avoid macros except for include guards

I have no comments on C# as a language. It will take a lot to persuade me that the world needs yet another proprietary language. It will be especially hard to persuade me that it needs a language that is closely integrated with a specific proprietary operating system.

Naturally, calling C++ a legacy language shows a bias (see legacy code). That aside, people are usually thinking of Java or C# when they ask such a question. I will not compare C++ to those languages, but I can point out that “modern” doesn’t necessarily mean “better”, and that both Java and C# are rooted in 1980s style OOP to an even greater extent than early C++ is.

C++ too slow for low-level work? No. If you can afford to use C, you can afford to use C++, even the higher-level facilities of C++ where you need their functionality. See Abstraction and the C++ machine model and the ISO C++ standards committee’s Technical Report on Performance.

That said, it is usually a really dumb idea to go and reinvent a wheel that boost already offers.

Please note that object-oriented programming is not a panacea. “OOP” does not simply mean “good” - if there are no inherent hierarchical relationships among the fundamental concepts in your problem then no amount of hierarchy and virtual functions will improve your code. The strength of OOP is that there are many problems that can be usefully expressed using class hierarchies - the main weakness of OOP is that too many people try to force too many problems into a hierarchical mould. Not every program should be object-oriented. As alternatives, consider plain classes, generic programming, and free-standing functions (as in math, C, and Fortran).

Should I use call-by-value or call-by-reference?
  • If you want to change the object passed, call by reference or use a pointer; e.g. void f(&X); or void f(*X);
  • If you don’t want to change the object passed and it is big, call by const reference; e.g. void f(const &X);
  • Otherwise, call by value; e.g. void f(X);

Consider what is probably the the best known and most infamous example of undefined behavior:

int a[10];
a[100] = 0; // range error
int* p = a;
// ...
p[100] = 0; // range error (unless we gave p a better value before that assignment)

؜

The C++ (and C) notion of array and pointer are direct representations of a machine’s notion of memory and addresses, provided with no overhead. The primitive operations on pointers map directly onto machine instructions. In particular, no range checking is done. Doing range checking would impose a cost in terms of run time and code size. C was designed to outcompete assembly code for operating systems tasks, so that was a necessary decision. Also, C — unlike C++ — has no reasonable way of reporting a violation had a compiler decided to generate code to detect it: There are no exceptions in C. C++ followed C for reasons of compatibility and because C++ also compete directly with assembler (in OS, embedded systems, and some numeric computation areas). If you want range checking, use a suitable checked class (vector, smart pointer, string, etc.). A good compiler could catch the range error for a[100] at compile time, catching the one for p[100] is far more difficult, and in general it is impossible to catch every range error at compile time.

How do I deal with memory leaks? By writing code that doesn’t have any. Clearly, if your code has new operations, delete operations, and pointer arithmetic all over the place, you are going to mess up somewhere and get leaks, stray pointers, etc. This is true independently of how conscientious you are with your allocations: eventually the complexity of the code will overcome the time and effort you can afford.

No I don’t recommend “Hungarian”. I regard “Hungarian” (embedding an abbreviated version of a type in a variable name) a technique that can be useful in untyped languages, but is completely unsuitable for a language that supports generic programming and object-oriented programming - both of which emphasize selection of operations based on the type an arguments (known to the language or to the run-time support). In this case, “building the type of an object into names” simply complicates and minimizes abstraction. To various extent, I have similar problems with every scheme that embeds information about language-technical details (e.g., scope, storage class, syntactic category) into names. I agree that in some cases, building type hints into variable names can be helpful, but in general, and especially as software evolves, this becomes a maintenance hazard and a serious detriment to good code. Avoid it as the plague.

I prefer to use underscores to separate words in an identifier (e.g, element_count) rather than alternatives, such as elementCount and ElementCount. Never use names with all capital letter (e.g., BEGIN_TRANSACTION) because that’s conventionally reserved for macros. Even if you don’t use macros, someone might have littered your header files with them. Use an initial capital letter for types (e.g., Square and Graph). The C++ language and standard library don’t use capital letters, so it’s int rather than Int and string rather than String. That way, you can recognize the standard types.

11 Apr 2014, tagged: #Cpp

C++11 Tip: Never capture value with [&] for std::async’s lambda

Consider this code:

#include <unistd.h>
#include <iostream>
#include <future>

std::future<void> threadstate;

void func()
{
    std::string name = "Hiro";

    auto thread = [&] {
        sleep(5);
        std::cout << name << std::endl;
    };

    threadstate = std::async(std::launch::async, thread);
}

int main()
{
    func();
    std::cout << "Exit now." << std::endl;
}

Will print:

Exit now.
*GARBAGE*

Because when thread finish the work and access name to print it, there won’t be any name variable - function which called the lambda is closed and the string is freed. Almost all standard C++ types tie their lifetime to current scope, so always copy value of local variable with [=] , or if the variable is big and you have to capture it by reference, make it global and capture with [] so it would throw an error if local one with the same name exists. Also make sure that all threads are closed on program exit.

Installing QtCreator with Clang on Windows

In previous post I described the process of getting Clang work on Windows, now the neat part - making it work with QtCreator IDE. It’s pretty straightforward actually, you don’t have to compile it to make it work now! All you have to do is to download latest beta, install it and add its \bin sub-folder to system’s PATH. Run qtcreator.exe from \bin folder.

Enable Clang parser by going to “Help” -> “About Plugins…” window and enabling ClangCodeModel plugin. Restart the app.

Also you have to setup your compile kit from “Tools” -> “Options…” -> “Build and Run” -> “Kits” tab. It won’t matter because we will setup our project with CMake and Ninja, so you can choose whatever compiler available on system (e.g. MinGW)

Now, open “File” -> “New File or Project…” window and choose “Plain C++ Project (CMake Build)” option. Specify build location and stop at “Run CMake” step. You should see “Ninja (Desktop)” configuration by default. Don’t hit “Run CMake” button yet because it will use MinGW from available kit, we should override it to Clang by modifying “Arguments” entry. Paste this line into it:

-DCMAKE_C_COMPILER_ENV_VAR="CC" -DCMAKE_CXX_COMPILER_ENV_VAR="CXX" -DCMAKE_C_COMPILER="C:/LLVM/bin/clang.exe" -DCMAKE_CXX_COMPILER="C:/LLVM/bin/clang++.exe" -DCMAKE_MAKE_PROGRAM="C:/Ninja/ninja.exe"

If you installed Ninja somewhere else, change it at CMAKE_MAKE_PROGRAM define. Now hit the “Run CMake” button, if all was set up right and Ninja with Clang are available at PATH system variable you should see this:

image

Now when you’ll try to hit “Run” project button, 'iostream' file not found error will be thrown. Since Clang distributed without C++ headers and libraries, we should include them from other source, in our case from MinGW folder which we used to compile LLVM in previous post. Add those include paths to CMake file:

include_directories("C:/MinGW/include/c++/4.8.2")
include_directories("C:/MinGW/include/c++/4.8.2/x86_64-w64-mingw32")
include_directories("C:/MinGW/x86_64-w64-mingw32/include")

Notice 4.8.2 in paths, change it if needed. Now it should compile project properly. Here’s how Ninja’s log look like (with -v flag for verbose info) during compilation:

image

Compiling LLVM and Clang on Windows with MinGW and Ninja

  1. Download latest MinGW-w64 compiler.
  2. Extract it as MinGW and add to PATH C:\MinGW\bin folder.
  3. Install Python 2.7 and add its folder to PATH
  4. Get CMake and add its \bin sub-folder to PATH
  5. Get Ninja and extract it to some folder ( C:\Ninja\ for example), adding it to PATH as well
  6. Download LLVM and Clang source code, extract LLVM to some location (say, C:\llvm-3.4\ ) and Clang into C:\llvm-3.4\tools\ folder, renaming extracted folder as clang
  7. Create C:\LLVM folder where build files will be placed.
  8. Run cmake-gui , specify folders and press “Configure”

    image

  9. Add -O3 compile flags, without it compile may fail throwing "file too big", "too many sections" errors

    image

  10. Choose Ninja as the generator for the project and click “Finish”
  11. Generate project files by clicking on “Generate” button
  12. Open console window (cmd.exe), cd into C:\LLVM folder, type ninja and hit enter
  13. Go get some coffee. Not much sugar, but lot of milk.

  14. When it’s done you should see something like this:

    image

  15. Add C:\LLVM\bin to PATH
  16. To test it, create simple source file like:

    #include <iostream>
    
    int main()
    { std::cout << "Clang on Windows. Success!"; }
    Save file as main.cpp and compile it with this command:
    clang main.cpp -std=c++11 -I"C:\MinGW\include\c++\4.8.2" -I"C:\MinGW\include\c++\4.8.2\x86_64-w64-mingw32" -I"C:\MinGW\x86_64-w64-mingw32\include" -lstdc++

    Notice 4.8.2 in paths, change it if needed.

  17. Run a.out and see the result.
03 Apr 2014, tagged: #Clang
What does the clang -cc1 option do?