Nie używaj rand(), C++ ma <random>

Dość często spotykam się z kodem wyglądającym w przybliżeniu tak:

int x = rand()%200-100;
int y = rand()%200-100;

Czy zauważyliście już błąd? Jeśli tak lub nie, to możliwe, że nie macie racji – nie da się z powyższego kodu wywnioskować jaka była intencja programisty – czy to miał być kod losujący wartość z przedziału [-100, 99] czy też [-100, 100].

Pomijając nieczytelność/niejawność zamiarów, rand ma jeszcze następujące problemy:

  • nie musi być bezpieczny w wielowątkowości,
  • RAND_MAX może wynosić zaledwie 32767,
  • nawet jeśli sam rand wypluwa wszystkie liczby z jednakowym prawdopodobieństwem, modulo ten porządek zakłóca.

Ciężko nie wspomnieć o słynnym wykładzie “rand() Considered Harmful”: [yt][ch9]

Co się dzieje z Pierunem?

Przez ostatnie kilka dni byłem na drugim końcu Polski (dosłownie, trasa Przemyśl-Szczecin to dramat), i nie bardzo miałem możliwości pracy nad rozwojem Pieruna (lub nawet codziennym postowaniem). Teraz wróciłem; najbliższe cele to:

  • edytor już istniejących postów,
  • paginacja,
  • pełna obsługa tagów (t.j. klikalne tagi).

Gdy zakończę powyższe będę mógł poważnie myśleć o przesiadce produkcyjnej na Pieruna (to by ewentualnie wymagało dodania jeszcze jakiegoś redirecta starych linków na nowe).

C++ gotcha: funkcje wirtualne i argumenty domyślne

Weźmy za przykład następujące klasy:

struct base
{
	virtual void foo(int value = 42)
	{
		cout << __PRETTY_FUNCTION__ << ": " << value << endl;
	}
};
 
struct derived : base
{
	virtual void foo(int value = 100) override
	{
		cout << __PRETTY_FUNCTION__ << ": " << value << endl;
	}
};

Nic niezwykłego, typowy dynamiczny polimorfizm. Każdy znający podstawy C++ powinien zdawać sobie sprawę, że w poniższym kodzie dwukrotnie zostanie wywołana funkcja derived::foo:

derived obj;
base* b = &obj;
derived* d = &obj;
b->foo();
d->foo();

Zaskakujące może jednak być faktyczne wyjście:

virtual void derived::foo(int): 42
virtual void derived::foo(int): 100

Dlaczego wywołania, które powinny być identyczne jednak takie nie są?

Argumenty domyślne w dziwnych miejscach – czyli również od nowicjuszy można się czegoś nauczyć

Jeśli chodzi o C++ to mam o sobie całkiem wysokie mniemanie. Niemniej jednak, nie ma nikogo kto by znał ten język w całości. Ostatnio na forum, w dziale Newbie, zobaczyłem pytanie zawierające kod zbliżony do następującego:

// foo.hpp
struct foo
{
    void bar(int baz);
};
 
// foo.cpp
void foo::bar(int baz = 42)
{
// ...
}

Moją pierwszą odpowiedzią było “to się nie ma prawa skompilować”.

Argument vs. parametr – które jest które?

Dość często mi się to myli, jest to więc kolejna doskonała okazja do sprawdzenia, czy zapisanie informacji wspomaga jej retencję.

W kilku słowach: parametr to zmienna/stała będąca częścią prototypu funkcji, a argument to konkretna wartość do niej przekazana.

void foo(int a);
 
int main()
{
    foo(42);
}

W powyższym przykładzie a jest parametrem, a 42 argumentem.

Źródła: 1, 2, 3

Links, lynx, w3m i dillo nie wspierają dostatecznie HTML5

Byłem szczęśliwy gdy szybkie google’owanie pokazało mi atrybutu formaction dla html-owych form. Niestety, podczas dzisiejszych testów zgodności (ręcznych) z linksem okazało się, że ten atrybut jest przez niego kompletnie ignorowany. Tak samo zachowują się pozostałe konsolowe przeglądarki (lynx, w3m) oraz prosta przeglądarka GUI: Dillo.

Wobec tego następujący kod będzie musiał zostać zmodyfikowany, wraz z metodą obsługującą POST w danej ścieżce:

button(type="submit", formaction='/preview_comment') preview!
button(type="submit", formaction='/send_comment') send

dbcache.d umie już cache’ować listy

Dzięki temu wszystkie wyszukania (po tagach, językach, autorach, etc) będą bardzo szybkie. Sama implementacja widoczna jest tutaj. Niestety, nie obyło się bez drobnej duplikacji kodu (“done is better than perfect”), którą trzeba będzie usunąć. Na szczęście nie będzie z tym wiele roboty.

Na maszynie testowej czas generowania listy spadł z 6ms do standardowych ~200µs.

Przy okazji miałem okazję pobawić się z variadic templatkami w D…