这是 C++ 中 "mutable" 的一个很好的用例吗?
Is this a good use-case of "mutable" in C++?
我有以下 class:
class MyClass
{
private:
mutable int* m_buffer;
public:
MyClass(void)
: m_buffer(nullptr)
{
}
void init(void)
{
m_buffer = new int[10];
}
// This is the only public interface to retrieve m_buffer
const int* evaluate(int param) const
{
for(int i = 0; i < 10; ++i)
m_buffer[i] = param*10;
return m_buffer;
}
};
我读到 mutable
class 成员应该在其状态不影响 class 外部状态时使用。在上面的代码中,成员 m_buffer
仅通过 evaluate()
方法检索。此方法将更改 m_buffer
的值,但新值仅取决于 param
参数。在此特定示例中 mutable
关键字的使用是否正确?
我可以通过以下方式避免使用 mutable
:
- 每次调用该函数时都分配一个新缓冲区。但是,这会使我的代码变慢,因为缓冲区通常有几千兆字节。
- 预先分配输出缓冲区并将其作为参数传递给
evaluate
函数。但是,这会使我的API更难understand/use。
- 声明
m_buffer
为 int* const
。但是,这行不通,因为由于设计决定,我无法在构造函数的初始化列表中分配 m_buffer
。
对于您显示的代码,您根本不需要使用 mutable
关键字。
在 const 成员函数中,this
指针是 const 限定的,那么成员也将是 const,对于 m_buffer
它将是 int* const
(注意它不是 const int*
),这意味着您仍然可以更改 m_buffer
指向的值,但不能更改它本身。
而在 evaluate()
中,您只是更改了 m_buffer
指向的值,而不是 m_buffer
本身,所以应该没问题。
我的意见是,当用户可以定义这样的场景时,这并不是一个好主意:
MyClass evaluator;
const int* arrResult1 = evaluator.evaluate(10);
//use of arrResult1
const int* arrResult2 = evaluator.evaluate(15);
//use of arrResult1 and arrResult2
在这种情况下,arrResult1 将被第二次调用 evaluate()
破坏。
你可以这样改:
class MyClass
{
private:
int* m_resultCache;
public:
MyClass(void)
: m_resultCache(nullptr)
{
}
~MyClass() { delete[] m_resultCache; }
const int* getResult() const { return m_resultCache; }
void evaluate(int param)
{
if (m_resultCache == nullptr)
m_resultCache = new int[10];
for(int i = 0; i < 10; ++i)
m_resultCache[i] = param*10;
}
};
我有以下 class:
class MyClass
{
private:
mutable int* m_buffer;
public:
MyClass(void)
: m_buffer(nullptr)
{
}
void init(void)
{
m_buffer = new int[10];
}
// This is the only public interface to retrieve m_buffer
const int* evaluate(int param) const
{
for(int i = 0; i < 10; ++i)
m_buffer[i] = param*10;
return m_buffer;
}
};
我读到 mutable
class 成员应该在其状态不影响 class 外部状态时使用。在上面的代码中,成员 m_buffer
仅通过 evaluate()
方法检索。此方法将更改 m_buffer
的值,但新值仅取决于 param
参数。在此特定示例中 mutable
关键字的使用是否正确?
我可以通过以下方式避免使用 mutable
:
- 每次调用该函数时都分配一个新缓冲区。但是,这会使我的代码变慢,因为缓冲区通常有几千兆字节。
- 预先分配输出缓冲区并将其作为参数传递给
evaluate
函数。但是,这会使我的API更难understand/use。 - 声明
m_buffer
为int* const
。但是,这行不通,因为由于设计决定,我无法在构造函数的初始化列表中分配m_buffer
。
对于您显示的代码,您根本不需要使用 mutable
关键字。
在 const 成员函数中,this
指针是 const 限定的,那么成员也将是 const,对于 m_buffer
它将是 int* const
(注意它不是 const int*
),这意味着您仍然可以更改 m_buffer
指向的值,但不能更改它本身。
而在 evaluate()
中,您只是更改了 m_buffer
指向的值,而不是 m_buffer
本身,所以应该没问题。
我的意见是,当用户可以定义这样的场景时,这并不是一个好主意:
MyClass evaluator;
const int* arrResult1 = evaluator.evaluate(10);
//use of arrResult1
const int* arrResult2 = evaluator.evaluate(15);
//use of arrResult1 and arrResult2
在这种情况下,arrResult1 将被第二次调用 evaluate()
破坏。
你可以这样改:
class MyClass
{
private:
int* m_resultCache;
public:
MyClass(void)
: m_resultCache(nullptr)
{
}
~MyClass() { delete[] m_resultCache; }
const int* getResult() const { return m_resultCache; }
void evaluate(int param)
{
if (m_resultCache == nullptr)
m_resultCache = new int[10];
for(int i = 0; i < 10; ++i)
m_resultCache[i] = param*10;
}
};