Вопрос правильности в C ++ - PullRequest
0 голосов
/ 12 октября 2009

У меня есть случайный вопрос о правильности констант.

Допустим, у меня есть класс-одиночка.

class Foo : public Singleton<Foo>
{
    friend class Singleton<Foo>;

public:
    std::wstring GetOrSet(const int id) const;

private:
    Foo();
    ~Foo();
    void LoadStringIntoMap(const int id, const std::wstring &msg);

    std::map<int, std::wstring> strMap;
};

Функции определены как таковые

std::wstring Foo::GetOrSet(const int stringId) const
{
    if ( strMap.find(stringId) == strMap.end() )
    {
        Foo::GetInstance()->LoadStringIntoMap(stringId, std::wstring(L"HELLO WORLD222"));
    }
    std::map<int, std::wstring>::const_iterator retStr = strMap.find(stringId);
    return retStr->second;
}

void Foo::LoadStringIntoMap(const int stringId, const std::wstring &msg)
{    
    strMap.insert(std::pair<int, std::wstring>(stringId, msg));
}

Если я непосредственно получаю вызов LoadStringIntoMap, я получаю сообщение об ошибке, что он не может преобразовать этот указатель из const Foo в Foo &. Это имеет смысл, поскольку вы вызываете неконстантную функцию из константной функции. Но почему это не проблема при вызове синглтона и внесении изменений через него.

Это просто действительно небезопасно?

Это то, что синглтон определяется как:

   template <typename T> class Singleton
{
protected:
    Singleton () {};
    ~Singleton () {};

public:
    static T *GetInstance()
    {
        return (static_cast<T*> (m_This));
    }

    static void Destroy()
    {
        if(m_This != NULL)
            delete m_This;
    }

    static void CreateInstance()
    {
        m_This = GetInstance();

        if (m_This == NULL)
        {
           m_This = new T;
        }
    }

private:
    // Unique instance
    static T *m_This;
};

template <typename T> T *Singleton<T>::m_This = NULL;

Ответы [ 5 ]

3 голосов
/ 12 октября 2009

GetInstance() возвращает не-const указатель. Поскольку функция GetInstance() связана не с самим объектом, а с классом, ее можно вызвать из функции const.

По сути, вы обманули себя из среды const; но тогда вы можете сделать это из любого контекста / состояния вашей программы (конфиденциальность членов не привязана к конкретным объектам, а только к классам). В этом случае вы должны самостоятельно позаботиться о безопасном использовании одноэлементных аксессоров.

1 голос
/ 12 октября 2009

Код иллюстрирует, что бессмысленно иметь константный указатель на синглтон, когда вы можете получить неконстантную ссылку на синглтон в любое время через глобальный геттер. Глобальный получатель говорит: «Конечно, любой может изменить объект в любое время. Это хорошо». Функция-член const говорит: «О, нет, было бы очень плохо модифицировать этот объект».

Если класс не был одноэлементным, так что не было уверенности, что this ссылается на тот же объект, который возвращает GetInstance, тогда это может иметь смысл во многих случаях. Так как они ссылаются на один и тот же объект, и все знают, что они делают, потому что это одиночный объект, они не могут быть оба правы.

Вы никогда не сможете предположить, что некоторый глобально доступный объект не будет изменен (по крайней мере, вы не можете предполагать, что система const поможет вам избежать его изменения - могут быть некоторые другие свойства класса, которые делают гарантии на модификации). Так что либо GetInstance небезопасно, либо мотивы человека, вызывающего функции-члены на const Foo, небезопасны, в зависимости от того, кто на самом деле прав, относительно того, должен ли объект быть изменен в данном бите кода. В этом случае я не уверен, в чем смысл определения каких-либо const функций-членов объекта, который является глобально изменяемым - если у кого-то есть постоянная ссылка на него, то откуда он взял эту ссылку и почему? И что заставляет кого-то думать, что функция с именем «Get OrSet » должна быть в первую очередь const?

Один из вариантов - для GetInstance возвращать const Foo&, но есть некоторые mutable переменные-члены для вещей, которые может изменить любой, в любое время, даже через константную ссылку. Но это зависит от того, для чего фактически предназначен Foo: mutable действительно должен использоваться только для таких вещей, как кэши, которые не изменяют "наблюдаемое" гарантированное поведение объекта.

1 голос
/ 12 октября 2009

Это не то, что это небезопасно, это просто совершенно нелогично. Если вы не хотите иметь константу this, то не указывайте функцию как const. Это так просто. В любом случае, компилятор не может выполнить большую оптимизацию.

Причина, по которой это работает, в том, что синглтон передает новый указатель this, НЕ унаследованный от родительской функции. Неважно, что они оба имеют один и тот же адрес. Один - const, который не может использовать функция. Один не

0 голосов
/ 12 октября 2009

Поскольку компилятор заботится только о доступе к this. Это не так далеко, как проверка всех путей, которые могут изменить ваш объект. Так что да, это работает. Это небезопасно? Это зависит :) Не должно быть в большинстве случаев, но уверен, что есть множество обстоятельств, которые могут заставить все это упасть.

0 голосов
/ 12 октября 2009

Да, это просто небезопасно.

У инструментов нет (простого) способа узнать, что const в Foo :: GetOrSet будет применяться к тому же экземпляру Foo, что и Foo :: GetInstance ().

'Singleton' не является политикой, которая что-либо значит для компилятора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...