Не будьте небрежными

facepalm

Этот небольшой пост навеян моей печалью по поводу текущего состояния дел в так называемом «production code». Да, я понимаю, что для коммерческого успеха чистота кода, его качество и красота совершенно неважны. Важно лишь одно — его работоспособность.

Но господа программисты, неужели это причина злоупотреблять и писать халатно код? Конечно жесткие ограничения по времени, неохота разбираться в сложном чужом коде, приводят, в конечном счете, к костылям или не совсем элегантным решениям. Но в данный момент речь не об этом. Речь о простых примитивных конструкциях языка.

Проблема

Не далее как несколько дней назад, мне пришлось разбираться в одном проекте. В ходе исследования я обнаружил примерно следующую конструкцию:

GetFoo()->do_something();

Что может подумать человек, увидивший эту конструкцию? Ну, наверное, он предположит, что это либо какой-то геттер текущего класса, либо же некая глобальная функция, возвращающая экземпляр класса (вернее, указатель на него). Но углубившись в код, начинаешь понимать в истинности слов «не всё то золото, что блестит». За всей ширмой включений, моим глазам предстал следующий код:

#ifndef COMMON_HPP_
#define COMMON_HPP_

#include "foo.hpp"

// ...

Foo foo;
#define GetFoo() (&foo)

#endif // COMMON_HPP_

О чем думали разработчики писав этот код — загадка. Данный код не то что просто некорректен с эстетической точки зрения (глобальная переменная, макрос, который ко всему еще маскируется под функцию), но и не выполняет своего предназначения. Очевидно же, что это попытка создать объект-синглтон, но попытка эта весьма неудачная. При подключении данного заголовочного файла в разных .cpp файлах мы получим ошибку линкера о множественном определении объекта foo. И это чудо, что проект использовал его только в одном модуле и все работало.

Решение

Как бы это сделал я? Да элементарно! Я бы просто вспомнил о таких чудесных механизмах как inline-функция и static переменная.

#ifndef COMMON_HPP_
#define COMMON_HPP_

#include "foo.hpp"

// ...

inline Foo* GetFoo()
{
    static Foo foo;
    return &foo;
}

#endif // COMMON_HPP_

В результате мы получим то, чего и добивались, но кроме этого у нас:

  • не будет макроса (который сам по себе опасен);
  • не будет проблемы при подключении заголовочного файла из разных модулей.

Идея данного поста?

Идея поста весьма проста: «не будьте халатными, господа программисты». Ведь написать предложенный мною вариант не сложнее оригинального, но мы сразу избежим ряда потенциальных проблем.

p.s: Я прекрасно понимаю, что уровень педантизма в каждом из нас развит по-разному, и возможно кто-то не согласится со мной. Но блог для того и нужен, чтобы выражать свои мысли и свои эмоции.