Lawful Evil #2 – Pilne Kolos z struktur

Treść prośby1 o pomoc wyglądała następująco:

Zadanie 1
Zdefiniuj strukturę opisującą książkę zawierającą pola (ilość stron, numer
biblioteczny, termin wypożyczenia) , oraz zdefiniuj strukturę opisującą datę. W
programie dynamicznie utwórz zmienną typu strukturalnego z polem typu
strukturalnego , następnie wczytaj z klawiatury wartości pól, po czym wczytane
informacje wydrukuj na ekranie. Przed zakończeniem programu zwolnij pamięć po
dynamicznie utworzonej zmiennej. (3 pkt)
Zadanie 2
Napisz funkcję, która zwraca jako wartość wskaźnik do zmiennej strukturalnej
opisującej książkę. Zadaniem funkcji jest zaalokowanie zmiennej oraz ustalenie
wartości jej pól (wartości pól zmiennej wczytujemy z klawiatury).
Napisz program testujący działanie funkcji.

Visual Studio

Wygląda na idealnego kandydata do tej kategorii.

1W sumie ciężko było powiedzieć czy to prośba, bo słowo “proszę” ani żadne podobne nie znajduje się w treści.

ZWI #1: Jak wykryć kontenery asocjacyjne w czasie kompilacji

Tym postem rozpoczynam kolejną serię – ZWI (Zapytane w Internecie). W planach jest co najmniej jeden wpis ;​) Posty będą przedstawiały pytania, na które odpowiedziałem na różnej maści forach, które (lub których odpowiedzi) uznałem za godne uwagi.

Na pierwszy ogień idzie następujące pytanie z forum 4programmers:

Mam prostą funkcję

template <typename Container, typename Value>
bool contains(const Container& container, const Value& value)
{
    return std::find(std::begin(container), std::end(container), value)
        != std::end(container);
}

Dla kontenerów asocjacyjnych (set, multiset, unordered_set, map itd.) można wykorzystać metodę find(), która jest szybsza niż globalne find(). Pytanie czy da się w prosty i elegancki sposób wykryć taką sytuację, żeby wywołać container.find(), bo nie uśmiecha mi się pisać specjalizacji dla każdego typu kontenera.

Lawful Evil #1 – kwadraty magiczne

Rozpoczynam nową serię: Lawful Evil. Jest to znana kategoria postaci z DnD, charakteryzująca się działaniem zgodnym z obowiązującym porządkiem, jednak zaprzeczającym jego duchowi.

W moim wykonaniu jest to wykonywanie zadań (domowych czy innych) zgodnie z literą zadania, ale w sposób taki, aby było jasne, że to parodia/żart. Zadania będą maksymalnie przekombinowane, mogą zawierać celowo rażące błędy i, w ramach możliwości, ich stopień skomplikowania uczyni je niemożliwymi do wytłumaczenia nauczycielowi/wykładowcy.

Jak przeładowywać operatory w mojej klasie?

Kiedy i które operatory przeładowywać?

Dość przewrotnie odpowiem: kiedy zajdzie taka potrzeba. Podstawą jest zachowanie logiki kodu (Samochod + Samochod nie ma zbyt sensu, ale Currency + Currency już tak) oraz konwencji języka (lub frameworka), np. w przypadku operatora <<.

Wyjście i wejście ze strumienia, czyli operatory << i >>

Tutaj nie ma wielkiej filozofii. Dobrze by było osiągnąć pełną serializację, t.j. zagwarantować poprawność kodu z listingu poniżej, ale w praktyce jest to więcej roboty niż to warte dla większości klas. Szczególnie, że nawet biblioteka standardowa nie zachowuje się w ten sposób, np. dla klasy std::string.

Jak łatwo zaimplementować w C++ operator porównania dla twojej klasy?

Biblioteka standardowa C++ w wielu miejscach oczekuje od typów, z którymi pracuje implementacji operatora< (alternatywą jest podanie własnego komparatora). Jest tak chociażby w std::sort, std::map lub std::binary_serch. Weźmy za przykład następującą klasę:

struct person
{
    string first_name;
    string last_name;
    string city;
    int year_born;
    bool is_male;
};

Aby posortować std::vector<person>, powinniśmy zaimplementować operator<, który spełnia strict weak ordering:

Bezpieczna zamiana jednostek w C++ część 1

sleep(300);

Ile śpimy? 0.3s (300ms)? 5 minut (300s)? A może parametrem powyższego sleep jest jeszcze inna jednostka? Bez zajrzenia do dokumentacji – albo kodu – nie ma na to pytanie odpowiedzi. Akurat w przypadku jednostek czasu C++11 wprowadził zestaw klas odpowiedzialnych za nie, więc można napisać taki zupełnie jednoznaczny kod:

this_thread::sleep_for(chrono::seconds(30));
this_thread::sleep_for(500ms); // C++14

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]