19 Mart 2018 Pazartesi

valgrind track-origins seçeneği

Giriş
track-origins seçeneğini kullanırsak, ilklendirilmemiş değişkenin nerede olduğunu görebiliriz. Eğer bu seçeneği kullanmadıysak hata raporunun en sonunda şöyle bir satır görebiliriz.
==9145== Use --track-origins=yes to see where uninitialised values come from
Bu seçeneği kullanırsak valgrind şöyle hata verir.
==3076== Conditional jump or move depends on uninitialised value(s)
Örnek
Elimizde şöyle bir kod olsun.
#include <iostream>
using namespace std;

int main() {
    int x;
    cout << x << endl;
    return 0;
}
Şöyle yaparız
$ valgrind --track-origins=yes ./a.out
==4950== Memcheck, a memory error detector
==4950== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4950== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4950== Command: ./a.out
==4950== 
==4950== Conditional jump or move depends on uninitialised value(s)
...
==4950==  Uninitialised value was created by a stack allocation
==4950==    at 0x400757: main (t.cpp:3)
==4950== 
Örnek
Elimizde şöyle bir kod olsun. x ilklendirilmemiş olarak kullanılıyor. Dolayısıyla valgrind hata verir.
#include <functional>
#include <iostream>

std::function<void()> callback;

void foo()
{
   int x;
   callback = [&]() { if (x > 5) std::cout << "hi"; };
}

int main()
{
   foo();
   callback();
}
Örnek
Elimizde şöyle bir kod olsun.
ListNodePtr convertBSTtoLinkedList(TreeNodePtr root)
{
  ListNodePtr list = malloc(sizeof(struct ListNode));
  list->key = root->key;
  if (root->right != NULL)
  {
    list->next = convertBSTtoLinkedList(root->right);    //line 80
  }
  ...
  return list;
}   
Bu kodda root->right == NULL durumunda list->next'e değer atanmıyor ve bu alan kodda kullanıldığı için valgrind uyarı veriyor.
Örnek
uninitialized data kopyalanırsa valgrind ilginç bir şekilde uyarı vermiyor. Açıklaması şöyle
It is important to understand that your program can copy around junk (uninitialised) data as much as it likes. Memcheck observes this and keeps track of the data, but does not complain. A complaint is issued only when your program attempts to make use of uninitialised data in a way that might affect your program's externally-visible behaviour.
Şöyle bir örnek verebiliriz. Burada memcpy paddingden dolayı belki ilklendirilmemiş belleği de kopyalıyor.
struct {
    char a;
    int b;
} s1, s2;

s1.a = '.';
s1.b = 31337;

memcpy (&s2, &s1, sizeof(s1));

std::pair Yapısı

Giriş
Şu satırı dahil ederiz.
#include <utility>
std::pair getFirst(), getSecond() gibi metodlar sunmaz. Bunun yerine first ve second isimli iki alan sunar. Ya da std::get ile kullanılabilir.

std::pair ve std::tuple birbirlerine çok benziyorlar ancak std::tuple<A,B> ile std::pair<A,B> farklı tiplerdir.

std::pair ve std::tuple STL ile mecburen kullanılıyor çünkü algoritmaların genel (generic) olması gerekiyor. Kendi kodumda ise, std::pair ve std::tuple yerine daha anlamlı struct veya class'lar kullanmayı tercih ediyorum.

Default constructor
std::pair verilen tiplerin default constructor'larını çağırır. Şu kod derlenmez.
class A
{
public:
    A (int a) {};
};

std::pair<std::string, A> p;

Constructor
Çevrim (Conversion) olmasına imkan tanır. İmzası şöyledir.
template< class U1, class U2 >
pair( const pair<U1, U2>& p );
Açıklaması şöyle
4) Initializes first with p.first and second with p.second. 
int tipindeki pair'den float tipine dönüşüm olmasına imkan tanır. Şöyle kullanabiliriz.
template<typename type> 
using point = std::pair<type, type>;

float dist(point<float> a, point<float> b)
{
    return pow(pow(a.first-b.first, 2) + pow(a.second - b.second, 2), 0.5);
}

int main() {
    std::cout << dist(point<int>{ 0, 0 }, point<int>{ 1, 1 });
    return 0;
}

< operator
std::pair < operatörünü overload eder. Önce firt elemanı karşılaştırır. Eğer aynı ise second elemanı karşılaştırır. Dolayısıyla sort algoritmalarında kullanılabilir. Örnek:
std::vector<std::pair<std::string, bool> > v;
std::sort(v.begin(), v.end());
is_trivial
std::pair trival değildir. Şöyle yaparız
std::cout << std::is_trivial<std::pair<int, int>>::value << std::endl;
Çıktı olarak şunu alırız.
0
is_trivially_copyable
std::pair trivally copyable değildir. Şöyle yaparız
std::cout << std::is_trivially_copyable<std::pair<int, int>>::value << std::endl;
Çıktı olarak şunu alırız.
0