26 Mayıs 2016 Perşembe

C++ ile Locale

Locale atamak

C++ programlarında global bir locale bulunur. Bu locale ilk açılışta std::locale::classic() olarak atanmıştır.

Global locale nesnesini değiştirmek için şu yöntemlerden biri kullanılabilir

1. "If a programmer wants to honor local conventions it should use corresponding locale objects. The static member function global of the class locale can be used to install a global locale object."

std::locale::global(std::locale(""));
Programın C locale'i başladığını ancak daha sonra değişitirildiğini gösteren küçük bir örnek
int main(void)
{
  std::cout << std::locale().name() << std::endl;//C locale ile başlar
  std::locale::global(std::locale(""));//Kullanıcının locale'ini atar
  std::cout << std::locale().name() << std::endl;
  std::locale::global(std::locale("C"));//C locale'ini atar
  std::cout << std::locale().name() << std::endl;
  return 0;
}
Çıktı olarak şunu verir
C
French_Canada.1252
C

2. setlocale metodu kullanılır.  std::setlocale yazısına taşıdım.

Locale İsimleri
Eğer belli bir ülkenin locale'i kullanılmak istenirse "" yerine locale ismini kullanmak gerekir.Ancak kullanılan string ismi platforma göre değişkenlik gösterir. Linux üzerinde seçili locale isimini görmek için "locale" komutu kullanılabilir.

Java gibi dillerde locale isimleri standartlaşmıştır.  Locale.getISOLanguages() ve Locale.getISOCountries() metodları kullanılabilir. Java'da şöyle yaparız:
public final class IsoUtil {
    private static final Set<String> ISO_LANGUAGES = new HashSet<String>
        (Arrays.asList(Locale.getISOLanguages()));
    private static final Set<String> ISO_COUNTRIES = new HashSet<String>
        (Arrays.asList(Locale.getISOCountries()));

    private IsoUtil() {}

    public static boolean isValidISOLanguage(String s) {
        return ISO_LANGUAGES.contains(s);
    }

    public static boolean isValidISOCountry(String s) {
        return ISO_COUNTRIES.contains(s);
    }
}





25 Mayıs 2016 Çarşamba

chrono sınıfları

C++11 chrono
Chrono içinde saat, süre, zaman noktası gibi kavramlar kullanılmış. Chrono için koda şu include eklenir.
#include <chrono>
1. Süre - Duration
chrono duration yazısına taşıdım.

2. Zaman Noktası - Time Point
Zaman noktaları saatin tipinden tanımlanır. Saatin epoch içindir. Süre ise epoch'tan beri geçen tick sayısı içindir.

A timepoint is defined as combination of a duration and a beginning of time (the so-calledepoch).
In other words, timepoint is defined as a duration before or after an epoch, which is defined by a clock

chrono::high_resolution_clock::time_point sınıfı
zaman değerini saklar
typedef std::chrono::high_resolution_clock my_clock;

my_clock::time_point start = my_clock::now();

3. Saatler
3 tane temel saat var. Bunlar high_resolution_clock, system_clock ve steady clock. Saatin sunduğu en önemli metod now(). Bunun dışında pek te önemli bir şey sunmuyor.

3.1 chrono::system_clock sınıfı
chrono::system_clock sınıfı yazısına taşıdım.

3.2 chrono::high_resolution_clock sınıfı

Sınıfın tanımında "represents the clock with the smallest tick period provided by the implementation" yazıyor.

high_resolution_clock sistemdeki en hassas saate alias olarak tanımlanır. En hassas saat system_clock veya steady_clock olabilir. En hassas saat system_clock ise durum vahimdir :)

Windows için notlar:
VS2012'de  high_resolution_clock system_clock ile aynı. Hatta sadece typdef olarak tanımlı.

Windows'ta en küçük çözünürlük 100 nanosaniye. Ancak çoğunlukla 100 nanosaniyede bir güncellenmiyor.

Çözünürlük şöyle bulunur.
cout << "resolution (nano) = " << (double) high_resolution_clock::period::num
        / high_resolution_clock::period::den * 1000 * 1000 * 1000 << endl;
Burada high_resolution_clock::period::den her saniyedeki tick sayısını verir. Her tick'in arasını saniye olarak bulup 1 milyar ile çarparak nanosaniyeye çeviriyoruz. Çıktı olarak şunu alırız.
resolution (nano) = 100
now metodu
Bir time_point  döndürür.
typedef std::chrono::high_resolution_clock my_clock;

my_clock::time_point start = my_clock::now();
3.3 chrono::steady_clock sınıfı
std::chrono::steady_clock Sınıfı yazısına taşıdım.

Hepsini Kullanmak
ScopedTimer örneği
#include <chrono>
#include <iostream>

using std::cout;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::endl;

class ScopedTimer {
public:
    ScopedTimer(const string& name)
    : name_(name), start_time_(high_resolution_clock::now()) {}

    ~ScopedTimer() {
        cout << name_ << " took "
        << std::chrono::duration_cast<milliseconds>(
                         high_resolution_clock::now() - start_time_).count()
        << " milliseconds" << endl;
    }

private:
    const string name_;
    const high_resolution_clock::time_point start_time_;
};






21 Mayıs 2016 Cumartesi

digraph ve trigraph karakterleri

Giriş
C++ dilinde digraph ve trigraph karakterleri kullanılabilir. Tablo şöyle
<%     {
 %>     }
 <:     [
 :>     ]
 %:     #
 %:%:   ##
 and    &&
 bitor  |
 or     ||
 xor    ˆ
 compl  ~
 bitand &
 and_eq &=
 or_eq  |=
 xor_eq ˆ=
 not    !
 not_eq !=
<: ve :> karakterleri
[ ve ] karakterlerine denk gelirler. Şu kod parçası
auto a = <:&:> { };
Şuna denktir
auto a = [&] { };
Şu kod parçası
do_it(<:&:> { std::cout << "Hello" << std::endl; }); //this
Şuna denktir.
do_it([&] { std::cout << "Hello" << std::endl; }); 

16 Mayıs 2016 Pazartesi

One Definition Rule

Açıklaması şöyle. Aynı isim alanı içinde aynı isime sahip iki struct tanımı olamaz.
if one .cpp file defines struct S { int x; }; and the other .cpp file defines struct S { int y; };, the behavior of the program that links them together is undefined.
file1.cpp dosyasında şu struct olsun
struct S2 { int a; char b; };
file1.cpp dosyasında şu struct olsun
struct S2 { int a; char bb; };
int main(){ return 0;}
Kodu derleyelim
g++ -std=c++11 file1.cpp file2.cpp
Kodun davranışı tanımsızdır (undefined). Ayrıca derleyici uyarı vermek zorunda değildir.



std::aligned_union

Giriş
aligned_union ve aligned_storage bellek için kullanılacak bir tip verir. Bunu typedef gibi düşünebilir. Bu tipden bir değişken yaratırız.

sizeof ile kullanım
Şöyle yaparız.
#include <iostream>
#include <type_traits>

int main() 
{
    using storage_type = 
        std::aligned_storage<sizeof(double), alignof(double)>::type;
    using union_storage_type =
        std::aligned_union<sizeof(double), double>::type;

    storage_type storage;
    union_storage_type union_storage;

    std::cout << sizeof(storage_type) << '\n';
    std::cout << sizeof(union_storage_type) << '\n';
    std::cout << sizeof(storage) << '\n';
    std::cout << sizeof(union_storage) << '\n';
    std::cout << sizeof(double) << '\n';
    return 0;
}
Çıktı olarak şunu alırız.
8
8
8
8
8
Eğer using olmadan kullanırsak şöyle yaparız.
template<typename ...Types>
struct variant
{
private:
  uint8_t index;
  typename std::aligned_union<Types...>::type storage;
};


5 Mayıs 2016 Perşembe

Virtual Metodlar

Virtual Table - VTable
C++ standardı polymorphism'in (çok biçimlilik) nasıl gerçekleşeceğini tanımlamaz. Ancak tüm derleyiciler vtable yöntemini kullanıyorlar. Bir gün başka bir üretici yeni bir yöntemle karşımıza çıkabilir.

Virtual metodlar derleyicinin sınıf için vtable üretmesine sebep olur. VTable bilgisinin nerede saklanacağı standart tarafından belirlenmiyor.

Microsoft derleyicisi şu şekilde saklıyor. Elimizde şöyle bir kod olsun.
class A {
  virtual Ax() {}
  int a, b;
};
class B {
  virtual Bx() {}
  int c, d;
};
class C : public A, public B {
  int foo, bar;
};
Object yerleşimi şöyledir.
A's VTable ptr
A's member variables.
B's Vtable ptr
B's member variables.
C's member variables.
Gcc ise vtable bilgisini object'in en sonuna yerleştirir.

De-Virtualization
Metodun virtual olmasına rağmen, derleyici tarafında vtable kullanılmasına gerek olmadığının tespit edilmesi ve verimlilik adına direkt çağrı haline getirilmesidir. Açıklaması şöyle
If the compiler can detect at compile-time that a particular call to a virtual member function, through a polymorphic type, will undeniably call a specific version of that function, then it is allowed avoid using the virtual dispatching logic, calling the function statically. That's behaving "as if" it had used the virtual dispatching logic, since the compiler can prove that this is the function that would have been called.

As such, the standard does not define when de-virtualization is allowed/forbidden....

Virtual Metodların Access Modifier Değiştirmesi
Ata sınıfta public olan bir virtual metodun, kalıtan sınıfta private yapılması. Bu kullanım şeklini hiç sevmiyorum ama bazı insanlar inatla kullanıyorlar. Şöyle yapılır
#include <iostream>

class A {
public:
  virtual void f() { std::cout << "virtual_function"; }
};

class B : public A {
private:
  void f() { std::cout << "private_function"; }
};

void C(A &g) { g.f(); }

int main() {
  B b;
  C(b);
}
Bir başka örnek
struct A {
    A(){ }
    virtual ~A(){ }
    A(A&&){ }
public:
    virtual void bar(){ std::cout << "A" << std::endl; }
};

struct B : public A{
private:
    virtual void bar(){ std::cout << "B" << std::endl; }
};

int main()
{
    A *a = new B;
    a -> bar(); //prints B
}
Java virtual bir metodun access modifier değiştirmesine izin vermiyor ve bence çok ta iyi yapıyor.
public class A{
    public void foo(){ }
}

public class B extends A{
    @Override
    private void foo(){ }  //compile-error
}

Pure Virtual
Diğer programlama dillerinde abstract diye bir anahtar kelime ile metodun pure virtual olduğu belirtilir. C++'ta şöyle belirtilir.
virtual void MyFunction() = 0; 
Aslında şöyle de yapılabilirdir.
pure virtual void MyFunction();
Sebebibini Bjarne Stroustrup şöyle açıklamış.
The curious = 0 syntax was chosen over the obvious alternative of introducing a new keyword pure or abstract because at the time I saw no chance of getting a new keyword accepted. Had I suggested pure, Release 2.0 would have shipped without abstract classes. Given a choice between a nicer syntax and abstract classes, I chose abstract classes. Rather than risking delay and incurring the certain fights over pure, I used the tradition C and C++ convention of using 0 to represent not there.
Yani tartışmalar daha fazla uzamasın istemiş.

Ata Sınıfta Pure Virtual Olmayan Bir Metod Sonradan Pure Virtual Yapılabilir
Saçma ama yine de yapılabiliyor. B metodu ilk ata sınıfımız. Bundan D kalıtır ve foo() metodunu pure virtual hale getirir. Böylece D'den kalıtan G foo() metodunu override etmek zorunda kalır.
class B // from a third party
{
public:
   virtual void foo();
};

class D : public B
{
public:
   void foo() override = 0; // allowed by gcc 4.8.2
   virtual void bar() = 0;
};

class G : public D
{
public:
   // forgot to reimplement foo
   void bar() override;
};

int main()
{
   G test;  // compiler error is desired
}