[英]C++11 const correctness for raw pointer getter
I've come across a small issue with const correctness in C++11 which I was hoping I could get clarified--I don't think it has already been asked! 我遇到了一个C ++ 11中具有const正确性的小问题,我希望我能得到澄清-我认为这还没有被问到!
Assume we have a class A, which contains an instance of class B which we want to expose. 假设我们有一个类A,其中包含我们要公开的类B的实例。 If we exposed it as a reference we would provide both const and non-const versions of the getter:
如果我们将其公开作为参考,我们将同时提供getter的const版本和非const版本:
class B;
class A final
{
public:
B& GetB()
{
return m_b;
}
const B& GetB() const
{
return m_b;
}
private:
B m_b;
};
However if we just had a pointer to B we would provide a getter which was const but returned a copy of the pointer to a non-const instance of B. This is because A doesn't OWN B, it only owns the the pointer, and therefore external modification of B doesn't change the state of A. (Note: I've come to this conclusion from personal experience; I've never found anything explicitly stating this is how this should work) 但是,如果我们只有指向B的指针,我们将提供一个为const的getter,但返回指向B的非const实例的指针的副本。这是因为A并不拥有B,它仅拥有该指针,因此,对B的外部修改不会改变A的状态。(注意:我是根据个人经验得出的结论;我从未发现任何明确说明其应如何工作的内容)
class B;
class A final
{
public:
A(B* b)
{
m_b = b;
}
A* GetB() const
{
return m_b;
}
private:
B* m_b;
};
This all makes sense so far, but what do we do if A owns a unique pointer (or shared pointer for that matter) to B? 到目前为止,这一切都说得通,但是如果A拥有指向B的唯一指针(或与此相关的共享指针),我们该怎么办? A now logically owns B--even if not literally.
A现在逻辑上拥有B-即使不是字面意义上的。 Up until now I've been following the second example above when exposing a raw pointer to a shared pointer, but since A logically owns B should I be doing something more similar to the first example?
到目前为止,在将原始指针公开给共享指针时,我一直遵循上面的第二个示例,但是由于A逻辑上拥有B,所以我应该做与第一个示例更相似的事情吗?
class B;
class A final
{
public:
A(std::unique_ptr<B> b)
{
m_b = std::move(b);
}
B* GetB()
{
return m_b.get();
}
const B* GetB() const
{
return m_b.get();
}
private:
std::unique_ptr<B> m_b;
};
In this case, if your design was correct when A
held a B
by value, then I'd use the same const/non-const accessors for the case when A
holds a B
by std::unique_ptr
. 在这种情况下,如果当
A
按值持有B
时您的设计是正确的,那么当A
通过std::unique_ptr
持有B
时,我将使用相同的const / non-const访问器。
Why? 为什么? Barring some additional means of ownership transfer away from
A
(such as a move assignment operator), in both cases A
owns a B
that will live and die with it. 在两种情况下,除非有一些其他的所有权转移方式(例如移动分配运算符)都离开
A
, A
拥有一个B
, B
将与之一起生活和死亡。 That in the latter case the B
instance happened to have been allocated separately on the heap and provided to the constructor is immaterial; 在后一种情况下,
B
实例恰巧是在堆上单独分配并提供给构造函数的,这无关紧要; its lifetime is the same. 它的寿命是相同的。
There's yet another variation of your example that may help settle your vacillation, assuming that we don't need to deal with the possibility of A::m_b
being null: 假设我们不需要处理
A::m_b
为null的可能性,那么您的示例还有另一种变体可以帮助您解决波动问题:
class B
{
// ...
};
class A final
{
public:
A() : m_b(std::make_unique<B>())
{}
B& GetB()
{
return *m_b;
}
const B& GetB() const
{
return *m_b;
}
private:
std::unique_ptr<B> m_b;
};
Here, A
clearly owns its B
, and offers no way to transfer ownership. 在此,
A
显然拥有其B
,并且没有办法转让所有权。 I don't know why we'd allocate B
on the heap here, but we can just to make a point. 我不知道为什么要在这里在堆上分配
B
,但是我们只能提出一点。 (Note that now A::GetB()
returns by reference rather than pointer.) With this example, would you still have a hard time deciding how to write A::GetB()
and whether to overload it on const? (请注意,现在
A::GetB()
通过引用而不是指针返回。)在此示例中,您仍然很难决定如何编写A::GetB()
以及是否在const上重载它吗?
While I do not have much authority to answer design questions, I would use something akin to has been proposed in @seh's answer , with the addition of a way to check for the null value of m_b
: 尽管我没有足够的权限回答设计问题,但我会使用类似于@seh的答案中提出的内容,并增加了一种检查
m_b
的空值的m_b
:
class B
{
// ...
};
class A final
{
public:
A(std::ptr<B> b) : m_b(std::move(b))
{}
bool HasB()
{
return m_b != nullptr;
}
B& GetB()
{
return *m_b;
}
const B& GetB() const
{
return *m_b;
}
private:
std::unique_ptr<B> m_b;
};
If you really can't do without pointers (legacy API), then it is more of a grey line. 如果您真的不能没有指针(旧版API),那么它更像是一条灰线。 I would declare both
const B* GetB() const
and B* GetB()
, since a common convention in C++11 is that raw pointers can be used to represent non-owning pointers . 我会声明
const B* GetB() const
和B* GetB()
,因为C ++ 11中的一个通用约定是原始指针可用于表示非所有者指针 。 Ultimately this would have to been indicated in documentation, though. 最终,这必须在文档中指出。
For an ownership situation it would IMHO be unnatural if a member function could allow modification of a part of a logically const
object, but that's a design issue. 对于所有权情况,如果成员函数可以允许修改逻辑
const
对象的一部分,恕我直言是不自然的,但这是设计问题。
However, do note that a raw pointer can be used to implement ownership. 但是,请注意, 可以使用原始指针来实现所有权。
For example, consider an internal array implemented with direct new
-ing and raw pointer. 例如,考虑使用直接
new
和new
指针实现的内部数组。 You would not want an interface that would break when/if that was replaced with a std::vector
for handling the storage. 您不希望当/如果用
std::vector
替换该接口来处理存储时会中断的接口。 And so the rule for whether to provide a const
/non- const
pair of accessor functions must be rooted in the design level, not in what the language permits for a given implementation of the design. 因此,是否提供访问函数的
const
/非const
对的规则必须植根于设计级别,而不是语言在给定的设计实现中所允许的语言。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.