1

我有一堂课:

class Nothing
{

    /// Constructor, Destructor, Copy and Assignment
    public:
    Nothing();
    ~Nothing();
    Nothing(const Nothing& clone);

    /// Operators
    const Nothing& operator=(const Nothing& other);

    /// Static Members
    private:
    static unsigned long long id_counter;
    static unsigned long long instance_counter;
};


Nothing::Nothing()
{
    m_name.clear();
    id_counter ++;
    m_id = id_counter;

    instance_counter ++;
}

Nothing::~Nothing()
{
    m_name.clear();
    instance_counter --;
}

Nothing::Nothing(const Nothing& other)
{

}

unsigned long long Nothing::id_counter = 0;
unsigned long long Nothing::instance_counter = 0;

请注意,我使用 unsigned long long 来计算类的实例。我应该改用 std::size_t 吗?

顺便说一句:如果我有一个类的实例,我会做这样的事情:

Nothing instance;
instance(Nothing()); // Calling copy constructor

会在调用复制构造函数之前调用析构函数吗?问的原因是我需要在我id_counter ++;instance_counter ++;复制构造函数内部吗?

4

4 回答 4

2

std::size_t 定义是特定于实现的,如您在en.cppreference中所见。在大多数实现中,您会发现它被定义为unsigned int.

因此,要回答您的问题,您可以使用它而不是unsigned long long您愿意,并且您的代码将保持可移植性(只要您实际上并不要求它是 64 位长),因为 std::size_t 是有保证的在每个 c++ 编译器上定义。如果该unsigned long long要求是强制性的(我怀疑因为您正在使用它例如计数),那么最好坚持使用unsigned long long.

instance(Nothing); // Calling copy constructor: Should this be `instance(Nothing())`?

这是不好的语法。如果您尝试copy ctor在新形成的实例上调用 ,则应调用Nothing copyInstance (Nothing());. 当然,这是一件非常愚蠢的事情,因为您正在复制一个“干净”的实例,您也可以调用Nothing copyInstance;相同的效果。

我需要 id_counter ++;和instance_counter ++;在我的复制构造函数里面?

由于您正在构建一个新实例,因此您绝对应该增加 instance_counter 。你没有指定什么 id_counter 计数(引用计数??)所以很难说。

会在调用复制构造函数之前调用析构函数吗?

在您的代码中,我没有看到将被调用的地方,dtor但是由于您在堆栈上进行分配,因此一旦到达其范围的末尾(下一次出现)instance,就会调用它的析构函数。instance}

于 2013-02-16T15:16:07.903 回答
2

std::size_tsizeof表达式的类型,通常是 STL 容器返回的size()类型capacity()。(从技术上讲,每个 STL 容器 typedef a size_type,但这几乎总是等价于std::size_t。)

除了具有奇怪内存模型的机器(例如,区分“近”和“远”指针的机器)之外,astd::size_t总是足够大,可以计算一次可以放入内存的所有对象。这不是直接保证,而是定义编写方式的副作用。

因此,std::size_t对于诸如实例计数之类的事物来说,它是一种自然类型。

请注意,这std::size_t是一个无符号类型。许多人认为您应该避免使用无符号类型,除非是表示实际位模式(例如,请参阅Google 样式指南)。通过使用无符号类型,一些算术运算可能会以令人惊讶的方式表现。如果您有一个导致您的实例计数变为负数的错误,则可能很难检测到,因为负值将环绕为非常大的正值。

就个人而言,我觉得这个论点没有说服力。有符号算术在处理上溢和下溢时也会以令人惊讶的方式表现。此外,当您尝试使用 STL 类型时,分配size()给带符号的值或将带符号的值与size()需要显式转换或禁用编译器警告进行比较。我不喜欢禁用编译器警告,特别是因为它们可以帮助您找到人们在建议避免使用无符号类型时担心的许多错误。

我会用std::size_t. 没有什么问题unsigned long long,但在主机平台上可能无法很好地扩展。

如果你想让你的选项保持开放,那么你可以在你的 Nothing 类中添加一个 typedef ,这样以后很容易改变主意:

/// Static Members
private:
typedef unsigned long long CounterType;  // consider std::size_t
static CounterType id_counter;
static CounterType instance_counter;

size_type如果您想匹配 STL 容器的样式,您甚至可以调用您的 typedef 。

于 2013-02-16T16:48:39.160 回答
1

我正在使用 unsigned long long 来计算类的实例。我应该改用 std::size_t 吗?

没有使用的理由,std::size_t也没有不使用的理由std::size_t。对于数组索引之类的东西,它是一种有用的类型(请参阅:unsigned int 与 size_t),但与您可以在任何给定程序中创建的最大对象数量完全无关。因此,只需根据您认为您将拥有的物品数量来选择您喜欢的物品。

会在调用复制构造函数之前调用析构函数吗?

您根本没有调用复制构造函数。事实上,你永远不能“调用”任何构造函数。当您创建一个新对象并从现有对象初始化它时,会自动调用复制构造函数,但您的代码中没有任何地方这样做。

我需要在我id_counter ++;instance_counter ++;复制构造函数内部吗?

是的。

于 2013-02-16T15:22:34.253 回答
1

从技术上讲,至少在不久的将来,两者都应该没问题。

正如所描述的linklinksize_t是运算符的返回值的类型,sizeof()并保证保持当前平台上可能的最大对象的大小。通常unsigned也是。

是的,使用unsigned long long不太可能在不久的将来造成任何问题。然而,size_t当您迁移到 128 位环境时,可能会在最大兼容性方面为您提供额外的优势。


但是,如果您的代码取决于至少unsigned long long具有0~2^64-1 的事实,那么切换到.size_t


是的,您需要更新复制构造函数中的计数器以使其正确。


PS我不明白你为什么要:

Nothing instance; 
instance(Nothing);

也许一些成员函数喜欢static Nothing Nothing::instance()获取一个新实例?// 我只是不明白为什么要在类型而不是现有实例上调用复制ctor 。

顺便说一句,您总是可以从构造函数和析构函数调用printf()flush()来检查它们的执行顺序。

于 2013-02-16T15:41:33.373 回答