C++Guns – RoboBlog blogging the bot

01.01.2016

rvalues, lvalues, xvalues, glvalues, prvalues WTF??

Filed under: Allgemein — Tags: — Thomas @ 20:01

Sehr zu empfehlen:
http://www.stroustrup.com/terminology.pdf


int   prvalue();
int&  lvalue();
int&& xvalue();

void foo(int&& t) {
  // t is initialized with an rvalue expression
  // but is actually an lvalue expression itself
}

GNhBF

— An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ]

— An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

— A glvalue (“generalized” lvalue) is an lvalue or an xvalue.

— An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expressions) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

— A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. —end example ]

Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects. For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types. —end note

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3055.pdf
http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

14.11.2015

ZipLib ist absoluter Schrott

Filed under: Allgemein — Tags: — Thomas @ 11:11

ZipLib von mindless-area ist absoluter Schrott. Vom c++11 Spirit seh ich nichts im Code aber das schlimmste ist die Laufzeit. Ein einfaches unzippen von zwei 30MB Datei mit ZipFile::Open() dauerte 3 Minuten. Das gunzip Programm schaff es in 5 Sekunden. 180sec vs. 5sec. Was macht der Typ da? Vor allem hat er den eigentlichen ZIP Algorithmus nicht mal implementiert. Er leitet es nur an die alten Libraries weiter. Finger weg!

13.11.2015

std::string trimmed std::string_view

Filed under: Allgemein — Tags: — Thomas @ 13:11

There is no trim() trimmed() member function in std::string. A free function is better.

Here is one nice solution which has a linear running time and not quadratic like using erase(). (Stupid programmer out there)
From:
http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring

std::string trimmed(const std::string &s) {
   auto wsfront=std::find_if_not(s.begin(),s.end(), [](int c){return std::isspace(c);});
   auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
   return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}
std::string_view trimmed(std::string_view s) {
    auto wsfront = std::find_if_not(s.begin(),s.end(), [](int c){return std::isspace(c);});
    // base() returns the forward iterator from reverse iterator returned by rbegin()
    auto wsback = std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
    return wsback <= wsfront ? std::string_view() : std::string_view(wsfront, wsback-wsfront); //  its a lower than there. F wordpress
}

27.10.2015

Enum Array replacement - some kind of

Filed under: Allgemein — Tags: — Thomas @ 18:10

Type safe enum class replace with normal class.
Used as an index (key) type for continuous containers like std::vector / std::array instead of std::map etc.

Pro: Fun.
Con: dynamic indice. myEnumIdx.somedata = 100000; can blow up the hole thing.

For static enum array see
http://fcppt.org/da/dcf/classfcppt_1_1container_1_1enum__array.html#af01f0518d2f63f4fd47eb5c510855c63
http://fcppt.org/d6/ddd/group__fcpptenum.html


#include <vector>

template<typename Key, typename Value>
class EnumArray {
public:
    
    Value & operator[](const Key& key) {
        return data[key];
    }
    
private:
    std::vector<Value> data;
};

class EnumType {
public:
    int someData = 0;
    
private:
    operator int() const {
        return someData;
    }
    
    template<typename EnumType, typename>
    friend class EnumArray;
};

class EnumType2 {
public:
    int someData = 0;
    
private:
    operator int() const {
        return someData;
    }
    
    template<typename EnumType2, typename>
    friend class EnumArray;
};

void testfunc() {
    EnumType myEnumIdx;
    
    // does not compile
    std::vector<int> vec1(10);    
    // error: ‘EnumType::operator int()’ is private
    // vec1[myEnumIdx] = 1; 
    
    // does compile cause EnumArray is a friend of EnumType and can array private implicit conversion operator to int
    EnumArray<EnumType, int> arr;
    arr[myEnumIdx] = 1;
    
    EnumType2 myEnumIdx2;
    // does not compile
    // error: no match for ‘operator[]’ (operand types are ‘EnumArray’ and ‘EnumType2’)
    // note:   no known conversion for argument 1 from ‘EnumType2’ to ‘const EnumType&’
    arr[myEnumIdx2] = 1;    
}


30.09.2015

c++11 move semantics - force it

Filed under: Allgemein — Tags: — Thomas @ 11:09

// $ g++ --std=c++11 -Wall -Wextra focemove.cpp
// $ ./a.out
// Yes using rvalue, move semantics
// Yes using rvalue, move semantics
// Oh no you forgot std::move somewhere. Deep copy occurs
//
// After delete unwanted ctor
// focemove.cpp: In function ‘void helper(std::vector< int >&&)’:
// focemove.cpp:44:20: error: use of deleted function ‘TestClass::TestClass(std::vector< int >&)’
// focemove.cpp:28:3: error: declared here
//
// testet with 4.7.4 - 5.2.1

#include < vector >
#include < iostream > 
#include < utility >

using namespace std;

// this class store biiiig data in a std::vector.
// If we initialize it with a const reference ctor a deep copy occurs.
// To prevent this, either dont proice a const reference ctor or better:
// forbid it at all.
class TestClass {
public:
  TestClass(vector< int > & other)
    : vec(other)
  {
    cout << "Oh no you forgot std::move somewhere. Deep copy occurs\n";
  }

// do we have to delete a const and non-const version here??
//   TestClass(const vector< int > & other) = delete;
//   TestClass(vector< int > & other) = delete;

  TestClass(vector< int > && other)
    : vec(other)
  {
    cout << "Yes using rvalue, move semantics\n";
  }
private:
  vector< int > vec;
};

void helper(vector< in t> && other) {
  // is other a rvalue or lvalue? It depends on the caller

  // here we forgot to use std::move(other)
  // other is a named rvalue and thus no move semantics are used
  TestClass a(other);

  // comment in this to test after fix TestClass constructor
//   TestClass a(move(other));
}

int main() {
  // this works all fine. All use move semantics
  TestClass(vector< int >());    // using temporaries, unnamed variables
  vector< int > other;
  TestClass(std::move(other)); // named variable other is converted to an unnamed with std::move

  // this call is okay
  helper(std::move(other));

  // this line triggers a error
  // cannot bind ‘std::vector< int >’ lvalue to ‘std::vector< int >&&’
  // helper(other);
  return 0;
}

29.07.2015

DerivedFunctor - fancy

Filed under: Allgemein — Tags: — Thomas @ 22:07

In C++11 kann man von einer Funktion erben. Krass.
Lambdas sind krass.
Das typedef musste sein, sonst hat er nicht compiliert. Ist vllt aber
nur ein Compilerbug und bald nicht mehr nötig.

auto foo = [](){return 42;};

class DerivedFunctor : public decltype(foo)
{
  typedef decltype(foo) type;
  public:
    DerivedFunctor(type foo)
    : type(foo)
    {
    }

    auto operator()() {
      cout << "DerivedFunctor::operator()\n";
      return type::operator()();
    }
};

int main() {
  DerivedFunctor t(foo);
  cout << t();
}

26.07.2015

Replace runtime constant wich template variables

Filed under: Allgemein — Tags: — Thomas @ 09:07

void version1(int i, int h) {
  // if(h) is evaluated every call
  if(h==0) {
  }
  else if(h==1) {
  }
  else {
  }
}

template
void version2(int i) {
  // if(h) is evaluated at compile time
  if(h==0) {
  }
  else if(h==1) {
  }
  else {
  }
}

void func(int h) {
  // h is a runtime constant for this function
  for(int i=0; i < 1e7; ++i) {
    version1(i, h);
  }

  // here,h is evaluated at runtime but outside the loop.
  // the compiler create three different version of version2 each for every h
  if(h==0) {
    for(int i=0; i < 1e7; ++i) {
      version2<0>(i);
    }
  }
  else if(h==1) {
    for(int i=0; i < 1e7; ++i) {
      version2<1>(i);
    }
  }
  else {
    for(int i=0; i < 1e7; ++i) {
      version2<2>(i);
    }
  }
}

int main() {
  int h=0;
  func(h);

  h=1;
  func(h);
}

10.06.2015

explicit constructor (Bug of the day 9)

Filed under: Allgemein — Tags: — Thomas @ 18:06

Hmm nicht einfach diesen Fehler zu erklären. Man braucht eine Basis Klasse, zwei abgeleitete Klassen und eine template Funktionen bei der man den Template Teil vergessen hat.

Die Idee ist folgende:
Irgendeine Funktion die irgendeinen Algorithmus ausführt, bekommt ihre Daten über einen Container per Funktionsparameter. Der Container kann alles mögliche sein: vector, list, stack array oder eigene Klassen die einen standard Container erweitern.
Für den Funktionsparameter, also den Container, benutzt man templates, damit der Algorithmus auf allen möglichen Datenstrukturen funktioniert und nur einmal implementiert werden muss.
Das ist gängige Praxis und funktioniert gut.

Nun habe ich zwei neue Klassen erstellt, die von z.B. std::vector erben. Im weiteren ist das die Basis Klasse. Diese Klassen speichern noch eine weitere Information. Welche, ist egal für dieses Beispiel. Nennen wir diese neuen Container Klassen Derived und Derived2.

Die Funktion sieht also so aus:

void func(const Derived &container);

Ich benutzt keine Templates, weil ich sie wie gesagt vergessen hatte. Das war Fehler Nr. 1. Der Code compilierte dennoch ;)

Da die neuen Container Klassen Derived und Derived2 beide von der Klasse Base erben, dachte ich, ein Constructor der eine Instanz der Base Klasse entgegen nimmt ist nicht soo verkehrt. Es ist dann bequem möglich seine Container mit den Standard Container von c++ zu initialisieren. Das war der zweite Fehler. Es ist im Grunde nicht falsch, nur man braucht es nicht, da wir ja templates nutzen. (Aber nicht implementieren).

Beim dritten Fehler habe ich die Coding Style Regeln nicht beachtet. Die besagt, dass man einen Constructor mit nur einem Argument als explicit deklarieren sollte. Siehe z.B. den Kram von google [1]

Normally, if a constructor can be called with one argument, it can be used as a conversion. Declaring a constructor explicit prevents it from being invoked implicitly as a conversion

Und genau das ist passiert. Ich habe func() mit einem Derived2 Object aufgerufen, und es wurde mangels templates in ein Derived Object umgewandelt. Dabei gingen natürlich die zusätzlichen Informationen verloren, welche diese Klassen speichern sollten.
Eine direkte Umwandlung der beiden Derived Klassen hatte ich nicht implementiert, da sie nicht sinnvoll sind.
Die Umwandlung erfolge über die Basis Klasse. Ein Derived2 Object ist ein Base Object. Und Derived kann mit Base Objecten initialisiert werden.

Das ist alles valid und der Compiler sieht kein Fehler. Aber es sollte zumindest ein Warning für den nicht expliciten Constructor geben. Zumindest bei GNU und clang habe ich nichts dergleichen gefunden. Der Intel Compiler kann es aber wohl [2] (Diagnostic 2304: non-explicit constructor with single argument may cause implicit type conversion).

Was lernen wir daraus? Coding Styles, und sich auch daran halten, retten Leben ;) Und nicht so bescheuert Programmieren ;)

Hätte man den Fehler durch ausgiebiges Testen der Funktion hätte finden können? Ja ich denke schon. Aber der Test muss gut sein. In meinem Fall hatte ich nur ein paar einfache Daten getestet und nichts bemerkt. Erst als ich einen anderen Fehler mit dem Debugger suchte ist es mir aufgefallen.

Im Anhang noch der Beispiel Code.explicitctor.cpp.zip

[1] https://google-styleguide.googlecode.com/svn/trunk/cppguide.html
[2] https://software.intel.com/en-us/forums/topic/335573

02.06.2015

QString to std::string (Bug of the day 8)

Filed under: Allgemein — Tags: , — Thomas @ 11:06
std::string class::func() const noexcept {
    return name.toLatin1().constData();
}

3 convertions. From QString to QByteArray to const char* to std::string. Lets see if it works. From Qt Docu

const char * QByteArray::?constData() const
Returns a pointer to the data stored in the byte array. The pointer can be used to access the bytes that compose the array. The data is '\0'-terminated unless the QByteArray object was created from raw data.

basic_string( const CharT* s, const Allocator& alloc = Allocator() )
Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The length of the string is determined by the first null character. The behavior is undefined if s does not point at an array of at least Traits::length(s)+1 elements of CharT.

Okay this should work, but can fail.

Using Qt function to convert QString to std::string is the better solution:

std::string QString::toStdString() const

29.05.2015

warning: conversion to 'float' from 'int' may alter its value [-Wconversion] (Bug of the day 7)

Filed under: Allgemein — Tags: , , — Thomas @ 22:05

Another bug of the day :D

You can do the following

float var = float(vari); // yes I know I'm loosing precision
int var = int(std::floor(varf)) // yes I know interger can overflow
int var = qFloor(varf) // Qt version

Same for double.

warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

Tricky one. Usually don't use unsigned types. The world is full of negative value. Use signed types.
Except for..
Array index. To access the full 32/64bit address space, one must use unsigned type.

Let variable data be a pointer/array.
data[i] is the same as data+i
Now variable i should have the same wide as data. Which is size_t. Type size_t is 32bit wide on 32bit system and 64bit otherwise.
New rule: Always use size_t for index variable while accessing data. Don't use int.

Type size_t is an unsiged type.
New rule: Never count backwards in for loops while accessing data.

Consider this endless loop
for(size_t i=data.size(); i >= 0; i--)

If i == 0 and i-- then i == 2^32-1 which is > 0. Damn.
There are a lot of solutions. Bad one and really bad ones. Here is my perfect one: You count forward. That is really easy and everybody understands what is going one and there are no surprises.
In the next line you subtract n-i-1 and volia. Perfect.

for(size_t ri=0; ri < data.size(); ri++) { size_t i = data.size() - ri - 1; I named the new loop variabl ri for reverse iterator. Don't forget to add -1. Arrays start by 0. You can of couse use std::reverse_iterator But hey, I love for loops!

« Newer PostsOlder Posts »

Powered by WordPress