考虑这个课程。
#pragma once
#include <memory>
#include <string>
class A;
class B;
class Test
{
public:
Test();
~Test();
private:
std::unique_ptr<A> m_a;
std::unique_ptr<B> m_b;
std::unique_ptr<std::string> m_string1; // 1
std::string m_string2; // 2
};
我总是尝试在头文件中转发声明类。但是,对于标准头文件,我不会这样做,前向声明模板类的typedef只是很痛苦。无论如何,如果我有标题可用 - 我应该更喜欢第一种方式还是第二种方式 - m_string1
或m_string2
?我觉得如果我混合指针和值类型,那么它看起来不一致。把一切都变成指针是个好主意吗?
答案 0 :(得分:1)
std::string
已经拥有一个动态结构(所以它本身就是一个指针)
毕竟,如果你认为一个字符串是一个“opaque类型”,所以不透明,你甚至不想包含它的标题,同样也应该是unique_ptr ...但你必须迟早停止,否则你将最后得到一类普通指针,大五(ctor,dtor,copy,assign,move,transfer)全部重新定义。但这每次都会重新实现智能指针。
还要考虑将一个类分解为太小的动态“细节”,将内容扩散到内存中,不允许(或更加困难)基于系统缓存的任何处理器优化。
如果那时你有一些模板,那么 pimpl 成语就变得毫无用处:你必须将整个类作为标题公开。
在我看来,你对这个成语的应用已经过深了。
答案 1 :(得分:1)
如果您打算这样做,请改用pImpl
:
class TestImpl;
class Test
{
public:
Test();
~Test();
private:
std::unique_ptr<TestImpl> m_;
};
并在.cpp文件中,创建一个包含所有数据的TestImpl
。
这将更好地隐藏您的实现细节,并减少间接,因为Test
的所有数据现在都是连贯的(聚集的),如果仍然删除了一个间接步骤。
答案 2 :(得分:0)
您希望它在堆上还是可能在堆栈上分配?有理由使用每种方法(例如对象生命周期),对情况使用适当的选择。如果你不需要,我觉得做指针管理毫无意义;即使你使用智能指针。
此外,像std::string
这样的类通常是指向堆分配字符串的指针。所以在这种情况下,您将为单个指针进行堆分配。堆分配比堆栈分配更昂贵,并且许多非常小的分配将倾向于快速分割堆空间,这使得分配器更难以找到合理大小的连续可用空间块。(/ p>)
IMO,一般的一致性很好,但为了保持一致性的一致性是僵硬和不切实际的。