4 Mart 2016 Cuma

String Algoritmaları

Giriş
Eğer kendi algoritmamızı yazıyorsak template şeklinde kodlamaya dikkat etmek gerekir. Parametremiz std::basic_string olmalı. Template olarak char, wchar kullanılabilir.

template<class T>
inline void myalgorithm(std::basic_string<T>& strInOut)
{...}
Trim
Trim string'in sağındaki ve solundaki boşlukları siler.
template<class TString>
static inline TString &trim_left(TString &s)
{
    s.erase(std::begin(s), std::find_if(std::begin(s), std::end(s),
                           std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

template<class TString>
static inline TString &trim_right(TString &s)
{
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), std::end(s));
    return s;
}

template<class TString>
static inline TString &trim(TString &s)
{
    return trim_left(trim_right(s));
}
Trim Right şöyle yazılabilir.
template<class T>
inline void removeOuterWhitespace(std::basic_string<T>& strInOut)
{
  constexpr auto delim[] = {T(' '),T('\t'),T('\n'),T(0)};
  const auto uiBegin = strInOut.find_first_not_of(delim);

  if (uiBegin == std::basic_string<T>::npos)
  {
    // the whole string is whitespace
    strInOut.clear();
    return;
  }

  const auto  uiEnd   = strInOut.find_last_not_of(delim);
  strInOut = strInOut.substr(uiBegin, uiEnd - uiBegin + 1);
}

24 Şubat 2016 Çarşamba

std::plus

Giriş
Metodun içi şöyle.
struct plus {
    template <typename A, typename B>
    auto operator()(const A& a, const B& b) const { return a + b; }
};
Direkt olarak şöyle kullanırız.
#include <functional>
#include <iostream>

int main()
{
   int a = 5;
   int b = 1;
   std::cout << std::plus<int>{}(a, b) << '\n';
}
Functor olarak şöyle kullanırız.
std::transform (v.begin(), v.end(), v1.begin(), foo.begin(), std::plus<int>());
Tabi lambda ile bence bütün bu functor'ların pabucu dama atıldı.

19 Şubat 2016 Cuma

Vector İle Yapılan Hatalar

Vector'ün Kendisi Üzerinde Dolaşırken Ekleme Yapmak - 1
Her ekleme end() iteratorünü invalid hale getirir. Aşağıdaki kod hatalı. Zaten Visual Studio assert hatası veriyor.
#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<int> v{3, 1, 4};

  v.reserve(6);

  for (auto e: v)
    v.push_back(e*e);

  for (auto e: v)
    cout << e << " ";

  return 0;
}
Benzer bir hata da şöyle.
int main() {
    // your code goes here
    vector<int> v;
    v.push_back(1);
    int count = 0;

    for(int elem: v){
        if(count<100)
        v.push_back(count);
        count++;
    }

    for(int elem: v)
    cout << elem << endl;

    return 0;
}
Vector'ün Kendisi Üzerinde Dolaşırken Ekleme Yapmak - 3
emplace_back iterator'leri invalid hale getirebilir. Bu da tanımsız davranışa sebep olabilir.
void use(std::string & s)
{...}

std::vector<std::string> v{"foo", "bar"};
auto & v_ref = v[0];
v.emplace_back("baz");
use2(v_ref); // Undefined Behavior

Son Eleman Hariç Dolaşmak
Vector nenesini, en son eleman hariç dolaşmak isteriz. Ancak vector boştur. Klasik bir unsigned int hatasıdır.
void fun (const std::vector<int> &vec) {
    for (std::size_t i = 0; i < vec.size() - 1; ++i)
        do_something(vec[i]);
}


14 Şubat 2016 Pazar

std::ispunct

Giriş
Belirtilen locale nesnesine göre karakterin noktalama işareti olup olmadığını döndürür.

C Locale ile Kullanım
Eğer locale vermezsek belirtilen karakterin unsigned char (0-255) ile temsil ediliyor olması gerekir.
Aşağıdaki kodda C locale kullanılıyor ancak unsigned char ile temsil edilemeyen bir karakter kullanılıyor. Dolayısıyla kod assertion veriyor.
int main() {
    ispunct('ø');
    cin.get();
    return 0;
}
Locale ile Kullanım
Aşağıdaki kodda UTF-8 ile kullanılıyor.
#include <iostream>
#include <locale>

int main()
{
    const wchar_t c = L'ø';

    std::locale loc("en_US.UTF-8");

    std::ispunct(c, loc);
}


3 Şubat 2016 Çarşamba

std::current_exception

Giriş
Tam olarak nerede ve nasıl kullanıldığını anlamadım. Thread içinde atılan exception'ı ana thread'e taşımak için şöyle yapılır.
void thread_function(std::exception_ptr* exception)
try {
    throw std::runtime_error("test exception");
}
catch(std::exception& e) {
    *exception = std::current_exception();
}

int main() {
    // Thread creation.
    std::exception_ptr other_thread_exception;
    std::thread t{thread_function, &other_thread_exception};

    // Thread termination.
    t.join();
    if(other_thread_exception)
        std::rethrow_exception(other_thread_exception);
}


2 Şubat 2016 Salı

Coroutine

Giriş
Corutine desteği C++ dilinin bir parçası haline geldi. Dolayısıyla dışarıdan bir kütüphane veya header dosyası kullanmaya gerek kalmadı.

C++20 ile Coroutine Nedir? 
Açıklaması şöyle
One of the most important new features in the C++20 is coroutines. A coroutine is a function that has the ability to be suspended and resumed. A function becomes a coroutine if it uses any of the following:

- the co_await operator to suspend execution until resumed
- the co_return keyword to complete execution and optionally return a value
- the co_yield keyword to suspend execution and return a value
Stack
Coroutine stack kullanmayacak yani stackless olacak. Stack olmaması her şeyin heap üzerinde olması anlamına gelmez.

Event Loop
C++ ile Coroutine kullanırken bir event loop'tan bahsedilmiyor.

19 Ocak 2016 Salı

Static Yerel (Local) Değişken

static local değişken metod ilk kez çağırıldığında ilklendirilir - non-trivial initialization
C++'ta bir nesnenin storage duration ve lifetime süreleri farklı şeylerdir. static local değişken için storage alanı uygulama ilk defa başlatılırken ayrılır.

Ancak ilklendirme yani lifetime'ın başlaması değişebilir. Eğer değişken trivial bir tipse tipse, hem storage hem lifetime uygulama açılırken başlatılabilir. Şöyle bir metodumuz olsun
{static int i = 0;}
i değişkenine 0 değeri en başta atanabilir. Metodun ilk kez çağrılmasını beklemeye gerek yoktur.

Eğer static local değişken constructor'a  sahip bir nesne ise, ilklendirme işlemi metod ilk kez çağrıldığında yapılır.Şöyle bir metodumuz olsun
void func1()
{
  static X i;
  ...
}
Bu metod ilk kez çağrıldığı zaman, X nesnesinin constructor metodu çağrılır.

static local değişken guard ile korunur
X nesnesi multi-threaded kod tarfından kullanılıyorsa, yaratılmasında problem olabilir. Bu yüzden derleyici bizim için X değişkeninden önce guard koyar.
void func1()
{
  static X i;
  static guard x_is_initialized;
    if ( __cxa_guard_acquire(x_is_initialized) ) {
        X::X();
        x_is_initialized = true;
        __cxa_guard_release(x_is_initialized);
    }
  ...
}
Gömülü bir platformda bir kez
Undefined reference to __cxa_guard_acquire
Undefined reference to __cxa_guard_release
hatasını bu yüzden almıştım.

static local değişken'in özyinelemeli kod kullanılması
Secure Coding için şöyle bir paragrah var.
Do not reenter a function during the initialization of a static variable declaration. If a function is reentered during the constant initialization of a static object inside that function, the behavior of the program is undefined. Infinite recursion is not required to trigger undefined behavior, the function need only recur once as part of the initialization.
Bu şu anlama geliyor. Static değişken kendini ilklendirmek için özyinelemeli kod kullanmamalı.
int foo(int i) {
  static int s = foo(2*i); // recursive call - undefined
  return i+1;
}
Böyle bir kod şu exception'a sebep olur.
terminate called after throwing an instance of '__gnu_cxx::recursive_init_error'
  what():  std::exception
static local değişken ve heap
Static local değişkeni heap'te yaratabiliriz.

class B {
  public:
   static const B* GetInstance() {
     static B* b = new B ();
     return b;
   }
};
Ancak uygulama sonlanırken önce static local değişken yok olacağı için heap'teki nesneyi silme şansımız olmayacaktır. Bu gibi durumlarda std::unique_ptr kullanmak iyi bir fikir.

class B {
  public:
   static const B* GetInstance() {
     static std::unique_ptr<B> b( new B() );
     return b.get();
   }
};

static local değişkenin yok edilmesi
static local değişkenlere program kapanırken dokunmamak gerekir.
If a function contains a block-scope object of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behavior if the flow of control passes through the definition of the previously destroyed block-scope object.

Aşağıdaki kod tanımsız iş yapar.
void theFunction()
{
  static std::unique_ptr<int> foo { new int(42) };
}

struct Creator
{
  Creator() { theFunction(); }
};


struct Destroyer
{
  ~Destroyer() { theFunction(); }
};

Destroyer d;
Creator c;

int main()
{}