我应该使用std :: size_t来计算我的类的实例吗?

时间:2013-02-16 15:11:42

标签: c++

我有一个班级:

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 个答案:

答案 0 :(得分: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到达结束时将调用其析构函数其范围(下一个}外观)。

答案 1 :(得分:2)

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

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

因此,std::size_t是实例计数之类的自然类型。

请注意std::size_t是无符号类型。许多人认为除了表示实际的位模式之外,你应该避免使用无符号类型(例如,参见Google Style Guide)。通过使用无符号类型,一些算术运算可能以令人惊讶的方式运行。如果你有一个错误导致你的实例计数变为负数,那么可能很难检测到,因为负值会回绕到一个非常大的正值。

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

我会使用std::size_tunsigned long long没有任何问题,但这可能无法与主机平台一起扩展。

如果你想让你的选项保持打开状态,那么你可以在你的Nothing类中添加一个typedef,这样可以在以后轻松改变主意:

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

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

答案 2 :(得分:1)

  

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

没有理由使用std::size_t,没有理由不使用std::size_t。对于像数组索引这样的东西,它是一个有用的类型(参见:unsigned int vs. size_t),但它根本不与你可以在任何给定程序中创建的最大对象数量相关联。因此,根据您认为您将拥有的对象数量,选择您喜欢的任何一个。

  

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

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

  

我的复制构造函数中是否需要id_counter ++;instance_counter ++;

答案 3 :(得分:1)

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

正如linklink所述,size_tsizeof()运算符的返回值的类型,并保证保持最大对象的大小目前的平台。它通常也是unsigned

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


但是,如果您的代码取决于unsigned long long 至少 0~2 ^ 64-1的事实,那么切换到size_t可能不是一个好主意。< / p>


是的,您需要更新复制构造函数中的计数器以使其顺利进行。


P.S。我不明白你为什么要这样做:

Nothing instance; 
instance(Nothing);

也许某些成员函数如static Nothing Nothing::instance()来获取新实例? //我只是不明白你为什么要在类型而不是现有的实例上调用copy-ctor。

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