C++ 中的 Const 正确性问题
我有一个关于 const 正确性的随机问题。
假设我有一个单例类。
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 &。这是有道理的,因为您从 const 函数内调用非常量函数。但是为什么在调用单例并通过它进行修改时这不是问题。
这真的不安全吗?
这就是单例的定义:
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;
I have a random question about const correctness.
Lets say i have a class that is a singleton.
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;
};
The functions are defined as such
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));
}
If i directly get call LoadStringIntoMap i get an error that it cannot convert this pointer from const Foo to Foo &. Which makes sense since your calling a non const function from within a const function. But why is this not an issue when calling the singleton, and doing modification through that.
Is this just really unsafe?
This is what singleton is defined as:
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
GetInstance()
返回一个非const
指针。由于函数
GetInstance()
并未绑定到对象本身,而是绑定到类范围,因此可以从const
函数调用它。本质上,您已经欺骗自己脱离了 const 环境;但是,您可以从程序的任何上下文/状态执行此操作(成员的私有性不绑定到特定对象,仅绑定到类)。在这种情况下,您必须自己注意单例访问器的安全使用。
GetInstance()
returns a non-const
pointer.As the function
GetInstance()
is not bound to the object itself, but class-wide, it may be called from aconst
function.Essentially, you have tricked yourself out of the
const
environment; but then, you could do that from any context/state of your program (privateness of members is not bound to specific objects, only classes). In this scenario, you have to care for a safe usage of the singleton accessors on your own.并不是说它不安全,而是完全不合逻辑。如果您不想使用常量 this 指针,则不要将函数指定为 const。就这么简单。无论如何,编译器不能在那里做太多优化。
它起作用的原因是因为单例传递了一个新的 this 指针,而不是从父函数继承的。它们都是相同的地址并不重要..其中一个是函数无法使用的 const 。一个不是
Its not that its unsafe its just totally illogical. If you don't want to have a constant this pointer than don't specify the function as const. Its that simple. The compiler can't do much optimisation there anyway.
The reason it works is because the singleton passes a new this pointer NOT inherited from the parent function. It doesn't matter that they are both the same address .. one is const which the function can't use. One isn't
该代码说明,当您可以通过全局 getter 随时获取对单例的非常量引用时,拥有指向单例的 const 指针没有多大意义。全局 getter 说:“当然,任何人都可以随时修改该对象。那很好”。 const 成员函数说:“哦,不,修改这个对象真的很糟糕”。
如果该类不是单例,因此无法确定
this
是否引用GetInstance
返回的同一个对象,那么这在很多情况下可能是完全有意义的案例。因为它们确实引用了同一个对象,并且每个人都知道它们引用的是同一个对象,因为它是单例的,所以它们不可能都是正确的。你永远不能假设某些全局可访问的对象不会被修改(至少,你不能假设 const 系统会帮助你避免修改它 - 类可能还有一些其他属性可以保证修改)。因此,要么
GetInstance
不安全,要么调用const Foo
上的成员函数的人的动机不安全,这取决于谁对于是否应该修改对象实际上是正确的在给定的代码位中。在这种情况下,我不确定定义全局可修改的对象的任何const
成员函数的意义是什么 - 如果有人对它有 const 引用,那么他们从哪里获得该引用从,为什么?是什么让人们认为一个名为“GetOrSet”的函数首先应该是 const 呢?一种选择是
GetInstance
返回const Foo&
,但有一些mutable
成员变量,任何人都可以修改,任何时间,即使是通过 const 引用。但这取决于 Foo 的实际用途:mutable
实际上应该只用于缓存之类的东西,这些东西不会修改对象的“可观察”保证行为。The code illustrates that it doesn't make a lot of sense to have a const pointer to a singleton, when you can grab a non-const reference to the singleton at any time, via the global getter. The global getter says, "sure, anyone at all can modify the object any time they like. That's fine". The const member function says, "oh, no, it'd be really bad to modify this object".
If the class wasn't singleton, so that it wasn't certain that
this
refers to the same object thatGetInstance
returns, then this might make perfect sense in a lot of cases. Since they do refer to the same object, and everyone knows they do because it's singleton, they can't both be right.You can't ever assume that some globally-accessible object won't be modified (at least, you can't assume the const system will help you avoid modifying it - there may be some other properties of the class which make guarantees about modifications). So either
GetInstance
is unsafe, or the motivations of the person calling member functions on aconst Foo
are unsafe, depending on who is actually correct as to whether the object should be modified in the given bit of code. In this case, I'm not sure what the point is of defining anyconst
member functions of an object which is globally modifiable - if someone has a const reference to it, then where did they get that reference from, and why? And what makes anyone think a function called "GetOrSet" should be const in the first place?One option is for
GetInstance
to returnconst Foo&
, but have somemutable
member variables for the things which it's OK for anyone to modify, any time, even through a const reference. But it depends what Foo is actually for:mutable
should really only be used for things like caches which don't modify the "observable" guaranteed behaviour of the object.是的,这只是不安全。
这些工具没有任何(直接)方式知道 Foo::GetOrSet 上的“const”将应用于与 Foo::GetInstance() 相同的 Foo 实例。
“单例”对于编译器来说并不是一个有任何意义的策略。
Yes, it's just unsafe.
The tools don't have any (straightforward) way of knowing that the 'const' on Foo::GetOrSet is going to apply to the same instance of Foo as Foo::GetInstance().
'Singleton' isn't a policy which means anything to the compiler.
因为编译器只关心对
this
的访问。它并没有检查所有可以更改对象的路径。所以是的,它有效。不安全吗?这取决于:)在大多数情况下不应该,但肯定有一些情况可以让它全部失败。Because compiler cares only about access to
this
. It doesn't go as far as checking all the paths that can change your object. So yeah, it works. Is it unsafe? It depends :) Shouldn't be in most cases but sure there's a set of circumstances that can make it all fall over.