C++11 原始指针获取器的常量正确性
C++11 const correctness for raw pointer getter
我在 C++11 中遇到了一个常量正确性的小问题,我希望我能得到澄清——我认为它还没有被问过!
假设我们有一个类 A,其中包含我们想要公开的类 B 的实例。如果我们将其公开为参考,我们将提供 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;
};
但是,如果我们只有一个指向 B 的指针,我们将提供一个 getter,它是 const 但返回指向 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;
};
到目前为止,这一切都是有道理的,但是如果 A 拥有指向 B 的唯一指针(或与此相关的共享指针(,我们该怎么办?A现在在逻辑上拥有B——即使不是字面意思。到目前为止,在将原始指针公开到共享指针时,我一直遵循上面的第二个示例,但是由于 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;
};
在这种情况下,如果您的设计在A
按值持有B
时是正确的,那么当A
按std::unique_ptr
持有B
时,我将使用相同的 const/non-const 访问器。
为什么?除非有一些额外的所有权A
转让方式(例如移动分配操作员(,否则在这两种情况下,A
都拥有一家将随之而生和消亡的B
。在后一种情况下,B
实例恰好在堆上单独分配并提供给构造函数是无关紧要的;它的寿命是相同的。
示例还有另一种变体可能有助于解决您的犹豫不决,假设我们不需要处理A::m_b
为空的可能性:
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;
};
在这里,A
显然拥有自己的B
,并且没有提供转让所有权的方法。我不知道为什么我们要在这里分配B
堆,但我们可以提出一个观点。(请注意,现在A::GetB()
按引用而不是指针返回。有了这个例子,你仍然很难决定如何编写A::GetB()
以及是否在 const 上重载它?
虽然我没有太多权限回答设计问题,但我会使用类似于@seh答案中提出的东西,并添加一种方法来检查 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;
};
如果你真的离不开指针(遗留API(,那么它更像是一条灰线。我会声明const B* GetB() const
和B* GetB()
,因为 C++11 中的一个常见约定是原始指针可用于表示非拥有指针。不过,最终必须在文档中指出这一点。
对于所有权情况,如果成员函数可以允许修改逻辑const
对象的一部分,恕我直言,这将是不自然的,但这是一个设计问题。
但是,请注意,原始指针可用于实现所有权。
例如,考虑使用直接new
-ing 和原始指针实现的内部数组。您不希望接口在/如果将其替换为用于处理存储的std::vector
时会中断。因此,是否提供const
/非const
对访问器函数的规则必须植根于设计级别,而不是语言允许给定的设计实现。
- 代理对象的常量正确性
- std::函数常量正确性未遵循
- C++ 常量正确性/缺少支持常量和非常量实例的类的常量构造函数
- 自定义引用包装器的常量正确性
- 如果我公开常量和非常量 API,我是否破坏了常量正确性?
- 如何强制实施有关指针数据成员的常量正确性
- 如何在C++的多维地图中实现常量正确性
- C++ 函数参数或声明中的常量正确性
- 结构初始化中的常量正确性
- 常量正确性编译错误到模板函数中的无效转换错误
- 如何在不违反常量正确性的情况下使用 std::lock_guard
- 非平凡变量的常量正确性
- 常量正确性和成员参考
- 常量正确性和shared_ptr,一个设计问题
- 观察者常量正确性
- 如何跨指针保持常量正确性
- 为了速度牺牲常量正确性可以吗
- file read()常量正确性
- C++NULL指针和常量正确性
- 共享指针和常量正确性