8 Ocak 2018 Pazartesi

alignas

Giriş
Bu yapı ile iki tane aynı nesneyi yanyana koyarsak ne kadar hizalama belleği kullanılacağını belirtiriz.

array
Şöyle yaparız.
typedef unsigned char Type;

const int N = 4;

alignas(64) Type buffer[N*64];
struct
Örnek
Şöyle yaparız.
struct alignas(16) small16 {
  char c;
};
Örnek
Elimizde şöyle bir kod olsun. Derleyici optimizedEqual() ve optimizedEqual2() kodları için hızlı kod üretiyor. Yani std::memcpy() ve std::memcmp() hızı çalışıyor. Ancak alanları tek tek karşılaştırma kodları hızlı değil.
struct Point {
  std::int32_t x, y;
};

[[nodiscard]]
bool naiveEqual(const Point &a, const Point &b) {
  return a.x == b.x && a.y == b.y;
}

[[nodiscard]]
bool optimizedEqual(const Point &a, const Point &b) {
  // Why can't the compiler produce the same assembly in naiveEqual as it does here?
  std::uint64_t ai, bi;
  static_assert(sizeof(Point) == sizeof(ai));
  std::memcpy(&ai, &a, sizeof(Point));
  std::memcpy(&bi, &b, sizeof(Point));
  return ai == bi;
}

[[nodiscard]]
bool optimizedEqual2(const Point &a, const Point &b) {
  return std::memcmp(&a, &b, sizeof(a)) == 0;
}


[[nodiscard]]
bool naiveEqual1(const Point &a, const Point &b) {
  // Let's try avoiding any jumps by using bitwise and:
  return (a.x == b.x) & (a.y == b.y);
}
Düzeltmek için şöyle yaparız. Point sınıfı 64 bit olacak şekilde hizalanırsa yani varsa aradaki "data alignment" byte'ları kaldırılırsa, derleyici 64 bşt karşılaştırma yapabilir.
struct alignas(std::int64_t) Point {
    std::int32_t x, y;
};
Primitive
Şöyle yaparız.
alignas(64) double bar;
Gcc Extension
Şöyle yaparız
typedef uint32_t __attribute__ ((aligned (64))) aligned_uint32_t;
std::cout << sizeof(aligned_uint32_t) << " -> " << alignof(aligned_uint32_t);
// Output: 4 -> 64
placement new
Örnek
Önce align edilmiş bir bellek alanı hazırlarız.
alignas(Foo) char memory[sizeof(Foo)];
Neden bilmiyorum ancak şu kullanım yanlış.
char memory[sizeof(Foo)];
Sonra placement new kullanarak şöyle yaparız.
::new (static_cast<void*>(buf)) Foo;
Örnek
Şöyle yaparız. Burada bellek alanı olarak daha büyük bir yer veriliyor.
alignas(int) unsigned char buffer[2*sizeof(int)];
 auto p1=new(buffer) int{};

4 Ocak 2018 Perşembe

std::uncaught_exceptions

Giriş
C++17 ile geliyor. Açıklaması şöyle.
It allows you to know if an object is being destroyed due to stack unwinding or through normal execution. This lets you know if you should do different kinds of cleanup. Consider a RAII object that will rollback a transaction if it is destroyed due to stack unwinding.
Örnek
Şöyle yaparız.
#include <iostream>

using namespace std;

struct A
{
  ~A()
  {
    cout << std::uncaught_exceptions() << endl;
  }
};

int main()
{
  try
  {
    try
    {

      A a1;
      throw 1;
    }
    catch (...)
    {
      A a2;
      throw;
    }
  }
  catch (...)
  {
    A a3;
  }   
}

2 Ocak 2018 Salı

Template argument deduction

Giriş
Template Argument Deduction explicit veya implicit olabilir.

explicit şöyle olur.
template<typename T>
void do_something(T value) {};

do_something<float>(6);  // T is float
implicit şöyle olur.
int x;

do_something(x);  // since first argument is T and x is int, T is int
Bir başka implicit örnek şöyle
template <typename T1,typename T2> void add(T2 a);
add<sample>(3);  // T1 is explcitly sample, T2 is implicitly int

STL ile Template Argument Deduction
template argument deduction STL ile bir çok algoritmada karşımıza çıkıyor. Genelde verilen dizinin büyüklüğünü derleyicinin bulması için kullanılıyor.

Bazı implicit örnekler şöyle.

std::end
std::end şöyle tanımlı. N boyutlu T tipini içeren bir array'i referans olarak alır.
template< class T, std::size_t N >
T* end( T (&array)[N] );
Metodun içi de muhtemelen şöyle
template< class T, std::size_t N >
T* end( T (&array)[N] )
{
    return array + N ;
}
Dolayısıyla şöyle kullanılabiliyor.
int arr[] = {1, 2, 3};
size = end(arr) - begin(arr);

Kendi Kodumuz İçin Implicit Diğer Örnekler
Örnek
Template kodlarda şöyle yaparız.
template <std::size_t sz)
void foo(double (&x)[sz]) {
   std::copy_n(x, sz, arr);
}
Örnek
recv diye bir metodumuz olsun
int recv(char* buf, int len) {
  int tmp = pos;
  while (len-- && pos < 26)
    *buf++ = arr[pos++];

  return pos - tmp;
}

template <size_t N>
int recv2(char(&array)[N]) {
  return recv(array, N);
}
Bu metodu şöyle çağırabiliriz.
char buffer[10];
recv2(buffer)


[[nodiscard]] Attribute

Giriş
C++17 ile geliyor. Açıklaması şöyle.
C++17 introduces the [[nodiscard]] attribute, which allows programmers to mark functions
in a way that the compiler produces a warning if the returned object is discarded by a
a caller; the same attribute can be added to an entire class type.
nodiscard Sadece Uyarı Amaçlıdır
Açıklaması şöyle.
The existing practice demonstrates there are cases when the programmer intentionally wants to discard the result of a nodiscard function, even though in most cases they do not. The existing nodiscard is a hint from the function designer to the function user, that immediately destroying the result is most likely not what you want, but it isn’t a straight­jacket and isn’t used as such.
Bazı yerlerde kullanıcıyı uyarmak gereklidir. Açıklaması şöyle.
Canonical examples include the return value of std::async where ignoring the return value would mean being not async at all, and the return value of a container’s empty() function where people sometimes confuse empty() and clear() and we don’t want them to think calling empty() has side effects if they call it by mistake.
Bazı yerlerde ise gereksizdir.Açıklaması şöyle.
1.Consider a queue data type with a .pop() method that removes an element and returns a copy of the removed element. Such a method is often convenient. However, there are some cases where we only want to remove the element, without getting a copy. That is perfectly legitimate, and a warning would not be helpful. A different design (such as std::vector) splits these responsibilities, but that has other tradeoffs.

2.Consider fluent interfaces, where each operation returns the object so that further operations can be performed. In C++, the most common example is the stream insertion operator <<. It would be extremely cumbersome to add a [[nodiscard]] attribute to each and every << overload.
Örnek
Attribute kalıtım ile geçmez. Şöyle yapamayız.
struct [[nodiscard]] Result {
};


struct DiscardableResult: Result {
};