1

I have a class:

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;

Notice I am using unsigned long long to count instances of the class. Should I use std::size_t instead?

As an aside: If I have an instance of a class, and I do something like this:

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

Will the destructor be called before the copy constructor is called? Reason for asking is do I need id_counter ++; and instance_counter ++; inside of my copy constructor?

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225

4 Answers4

2

std::size_t definition is implementation specific, as you can see in en.cppreference. In most implementations you will find it is defined as unsigned int.

So to answer your question, you can use it instead of unsigned long long if you prefer, and your code will remain portable (as long as you don't actually require it to be 64-bit long) in the sense that std::size_t is guaranteed to be defined on every c++ compiler. If the unsigned long long requirement is a mandatory (which I doubt since you are using it for instance count) then its best to stick with unsigned long long.

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

This is bad syntax. If you are trying to invoke the copy ctor on a newly formed instance you should call Nothing copyInstance (Nothing());. Of course that's a very silly thing to do since you are copying a "clean" instance, you might as well have called Nothing copyInstance; to the same effect.

do I need id_counter ++; and instance_counter ++; inside of my copy constructor?

You should definitely increment instance_counter since you are constructing a new instance. You didn't specify what id_counter counts (reference count??) so it's hard to say.

Will the destructor be called before the copy constructor is called?

Nowhere in your code do I see a place where the dtor will be called but since you are allocating instance on the stack, its destructor will be called once instance reaches the end of its scope (next } appearance).

eladidan
  • 2,634
  • 2
  • 26
  • 39
  • The relevance is the effect on portability when using std::size_t but I expanded the answer to clarify – eladidan Feb 16 '13 at 15:24
  • The question isn't "how portable is `std::size_t`?" It's "should I use `std::size_t` here?" – Lightness Races in Orbit Feb 16 '13 at 15:29
  • "should I use std::size_t here?" doesn't specify concerns for using/not using std::Size_t. I chose to answer with regard to portability because as far as I can tell it's the only concern that could affect whether to use it or not. There is nothing factually wrong with my answer and it addresses the original question's concern so I really don't see the reason for the downvote. – eladidan Feb 16 '13 at 15:33
  • The question is: `I am using unsigned long long to count instances of the class. Should I use std::size_t instead?` Your answer _is_ better now that you added the paragraph that begins "so to answer your question". – Lightness Races in Orbit Feb 16 '13 at 15:42
  • `Nowhere in your code do I see a place where the dtor will be called `That'd be, when `instance` goes out of scope. Which C++ book are you using, please? – Lightness Races in Orbit Feb 16 '13 at 15:51
  • Oh, the rest of the sentence that totally contradicts the first part of the sentence? Sure I did. – Lightness Races in Orbit Feb 16 '13 at 15:55
  • In the scope of the code the OP gave, no dtor is called. Out of the scope of his code, when instance goes out of scope, its dtor will be called. And that is in so many words, exactly what I said. – eladidan Feb 16 '13 at 16:02
  • Hah, touché. I'll give you that. – Lightness Races in Orbit Feb 16 '13 at 16:06
  • @LightnessRacesinOrbit, you have managed to cause more problems than solutions here. – FreelanceConsultant Feb 16 '13 at 17:16
  • @EdwardBird: I have done nothing but attempt to give _you_ the best and most accurate information that you can get, by identifying misleading and/or inaccurate statements in the comments and answers. As you can see, it led to this answer being _vastly_ improved to the point at which you were able to accept it. You're welcome. Yet again, as you have done elsewhere, you seem very hostile to your free volunteers. In fact it is _your_ comment that adds zero value. I think I shan't be participating on your questions any longer. – Lightness Races in Orbit Feb 16 '13 at 17:27
  • @LightnessRacesinOrbit Please see to it that you do. – FreelanceConsultant Feb 16 '13 at 17:37
  • @EdwardBird: And now, just for that, I shall participate in each and every one! See you soon – Lightness Races in Orbit Feb 16 '13 at 17:37
  • @LightnessRacesinOrbit surely this is childish? – FreelanceConsultant Feb 16 '13 at 17:38
  • @EdwardBird: I take writing extensively detailed technical answers to SO questions quite seriously; I do not believe that it is childish. However, this comment thread is becoming rather childish, so I'm going to leave you to it. – Lightness Races in Orbit Feb 16 '13 at 17:39
  • @LightnessRacesinOrbit the irony is that you take this too seriously, and yet you are behaving immaturely at the same time. – FreelanceConsultant Feb 16 '13 at 17:48
  • @EdwardBird: Fascinating. Do go on. – Lightness Races in Orbit Feb 16 '13 at 17:48
2

std::size_t is the type of a sizeof expression and usually the type returned by size() and capacity() of the STL containers. (Technically, the STL containers each typedef a size_type, but that's almost always equivalent to std::size_t.)

Except for machines with weird memory models (e.g., one that distinguishes between "near" and "far" pointers), a std::size_t will always be large enough to count all of the objects that you can fit into memory at one time. This is not a direct guarantee, but a side-effect of the way the definitions are written.

Therefore, std::size_t is a natural type for things like instance counts.

Note that std::size_t is an unsigned type. Many people believe you should avoid unsigned types except for representing actual bit patterns (for example, see the Google Style Guide). By using an unsigned type, some arithmetic operations may behave in surprising ways. If you had a bug that caused your instance count to go negative, it might be hard to detect, because a negative value will wrap around to a very large positive value.

Personally, I find that argument unpersuasive; signed arithmetic also behaves in surprising ways when dealing with overflow and underflow. Also, when you're trying to use STL types, assigning size() to a signed value or comparing a signed value to size() requires explicit casts or disabling compiler warnings. I dislike disabling compiler warnings, especially since they can help you find many of the bugs that people fear when they suggest avoiding unsigned types.

I would used std::size_t. There's nothing wrong with unsigned long long, but that might not scale as well with the host platform.

If you want to keep your options open, then you can add a typedef to your Nothing class, which makes it easy to change your mind later:

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

You could even call your typedef size_type if you want to match the style of the STL containers.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
1

I am using unsigned long long to count instances of the class. Should I use std::size_t instead?

There's no reason to use std::size_t and no reason not to use std::size_t. It's a useful type for things like array indices (see: unsigned int vs. size_t), but does not correlate at all to the maximum quantity of objects that you can create in any given program. So just choose whichever you like based upon how many objects you think you're going to have.

Will the destructor be called before the copy constructor is called?

You didn't call the copy constructor at all. In fact you can never "call" any constructor. The copy constructor is automatically invoked when you create a new object and initialise it from an existing object, but nowhere in your code do you do that.

do I need id_counter ++; and instance_counter ++; inside of my copy constructor?

Yes.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

Technically, both should be okay, at least in the near future.

As is described link and link, size_t is the type of the return value of sizeof() operator and is guaranteed to hold the size of the largest object possible on the current platform. It's usually unsigned also.

And yeah, using unsigned long long is unlikely to cause any problem in the near future. Yet size_t might gives you an extra advantage when you migrate to, say, 128bit environment, on maximum compatibility.


But if your code depends on the fact that unsigned long long has at least 0~2^64-1 it's probably not a good idea to switch to size_t.


yes, you need to update the counter in your copy constructor to get it straight.


P.S. I don't see why you would want to:

Nothing instance; 
instance(Nothing);

maybe some member function like static Nothing Nothing::instance() to get a new instance? // I just don't see why you would want to call a copy-ctor on a type instead of an existing instance.

And BTW you can always call printf() and flush() from constructors and destructors to examine their order of execution.

Community
  • 1
  • 1
phoeagon
  • 2,080
  • 17
  • 20