阅读层面
void foo(Data* data);
void bar(const Data* data);
对于 foo
,可能其实现中并不会修改 data
的内容,但是调用者无法知道这一点,因此调用 foo
时,需要考虑 data
的内容是否会被修改。即使查看过 foo
的实现,并不会实际修改 data 的内容,但是 foo
的实现可能会在后续发生变化,而调用者无法感知这一点。因此调用 foo
时,始终存在潜在的风险,每次使用 foo
时,都需要重新检查 foo
的实现,以确保 data
的内容不会被修改。
对于 bar
,调用者可以放心地传递 data
的地址,因为 bar
保证不会修改 data
的内容。即使 bar
的实现发生变化,只要 const
限定符不被移除,调用者就不需要关心 bar
的实现细节。
调用开销层面
void foo(QByteArray& ba)
{
const char* data = ba.data();
for (int i = 0; i < ba.size(); i++) {
int a = data[0];
int b = data[1];
int c = data[2];
// do something...
}
}
QByteArray
的部分实现如下(有所精简):
inline char QByteArray::at(int i) const { return d->data()[i]; }
inline char QByteArray::operator[](int i) const { return d->data()[i]; }
inline char *QByteArray::data() { detach(); return d->data(); }
inline const char *QByteArray::data() const { return d->data(); }
inline const char *QByteArray::constData() const { return d->data(); }
inline void QByteArray::detach() {
if (d->ref.isShared() || (d->offset != sizeof(QByteArrayData)))
reallocData(uint(d->size) + 1u, d->detachFlags());
}
首先得到如下结论:
char *QByteArray::data()
会调用QByteArray::detach
,QByteArray::detach
会调用QByteArray::reallocData
申请空间,存在额外开销。QByteArray::constData()
不存在额外开销。
由此得到优化方案一:
将 ba.data()
改为 ba.constData()
,可以避免 QByteArray::detach
的调用,减少额外开销。
void foo(const QByteArray& ba)
{
const char* data = ba.constData();
for (int i = 0; i < ba.size(); i++) {
int a = data[0];
int b = data[1];
int c = data[2];
// do something...
}
}
继续观察,发现结论:
foo
不需要修改ba
的内容,仅需要读取ba
的内容,因此data
的类型是const char*
。const char *QByteArray::data() const
也不会调用QByteArray::detach
,不存在额外开销。
如何才能调用 const char *QByteArray::data() const
而不是 char *QByteArray::data()
呢?可以将 foo
的参数改为 const QByteArray& ba
,这样 ba.data()
就会调用 const char *QByteArray::data() const
,而不是 char *QByteArray::data()
。
由此得到优化方案二:
将 foo
的参数改为 const QByteArray& ba
,可以避免 QByteArray::detach
的调用,减少额外开销。
void foo(const QByteArray& ba)
{
const char* data = ba.data();
for (int i = 0; i < ba.size(); i++) {
int a = data[0];
int b = data[1];
int c = data[2];
// do something...
}
}
继续观察,发现:
data
的作用仅仅是为了使用[]
,调用者似乎不知道QByteArray::operator[]
的存在。
由此得到优化方案三:
移除 data
,直接使用 ba[index]
:
void foo(const QByteArray& ba)
{
for (int i = 0; i < ba.size(); i++) {
int a = ba[0];
int b = ba[1];
int c = ba[2];
// do something...
}
}