6

This is a best practices question. I am making an array

type * x = malloc(size*sizeof(type));

AFAIK sizeof gives a return value of size_t. Does that mean that I should use a size_t to declare, or pass around size? Also when indexing the array should I also use a size_t for the index variable? What is the best practice for these these? This is not something that they taught in school, and now that I'm getting into serious c++ I want to know.

Also if anyone has references of where I can find best practices for this kind of stuff it would be helpful? Kind of an etiquette for programmers book.

EDIT: The malloc should be cudaHostAlloc, or cudaMalloc, since I am developing a class that stores an array simultaneously on the device and host, and updates both at the same time. So malloc here is just a place holder for what I'll actually be doing.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
Andrew Redd
  • 4,632
  • 8
  • 40
  • 64
  • 1
    A good "best practice" is using `sizeof` with the variable in use: `type * x = (type*) malloc( size*sizeof *x );` That way if you later update the type in the left hand size you won't need to update the right hand side (`sizeof(type)`) – David Rodríguez - dribeas Oct 27 '10 at 16:02
  • 5
    A good best practice for C++ is not to use `malloc()`. Why are you using it? – David Thornley Oct 27 '10 at 16:18
  • 1
    I edited in the question that the malloc is simply a place holder to show that I am dynamically allocating memory. I the final implementation I will be using the cuda interface to get at pinned memory ang gpu memory. So no i will not be really using malloc, but what I will actually be doing is more complicated than the question requires. – Andrew Redd Oct 27 '10 at 17:15

5 Answers5

7

In general, I use whatever minimizes the number of implicit or explicit casts and warning errors. Generally there is a good reason why things are typed the way they are. size_t is a good choice for array index, since it's unsigned and you don't generally want to access myarray[-1], say.

btw since this is C++ you should get out of the habit of using malloc (free) which is part of CRT (C runtime library). Use new (delete), preferably with smart pointers to minimize manual memory handling.

Once you have mastered the basics, a good practices reference (language-specific) is Effective C++ by Scott Meyers. The logical next step is Effective STL.

Community
  • 1
  • 1
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • 1
    One advantage with using int as an index is that you can iterate downwards and have a termination condition that checks if the index is >= 0. – Johan Kotlinski Oct 27 '10 at 16:05
  • 2
    True - or, you could use `array::rbegin()` and `array::rend()` – Steve Townsend Oct 27 '10 at 16:09
  • @steve - That is iff you've caught onto the best practice of using "smart" arrays rather than the raw types. – Edward Strange Oct 27 '10 at 16:26
  • @Noah - even without that, it's possible (and faster) to use pointer arithmetic not indices. Many STL algorithms work with pointer ranges too. – Steve Townsend Oct 27 '10 at 16:28
  • I'd agree with that. Unfortunately I don't believe there's a pointer->iterator wrapper that would be necessary for a reverse iterator. I'm also not 100% sure iterating to one less than the start of an array is OK from the standard's POV. I seem to recall a big discussion somewhere at one point that resulted in the fact that some architectures can actually have problems with first-1 and last+2. For most purposes I doubt that matters though. – Edward Strange Oct 27 '10 at 16:35
  • @Inverse - yes but the point is to express intended semantics of the index variable, not *per se* to prevent bad code from being written. – Steve Townsend Oct 27 '10 at 17:15
  • In most cases it is better to use std::vector than new/delete – Petter Oct 27 '10 at 17:42
  • @Ben, agreed, but in context (OP is new to C++) new/delete is a good first step vs `malloc/free`. Since I see this is CUDA, I doubt `vector` is available. – Steve Townsend Oct 27 '10 at 17:51
  • @Steve: In most cases it is better to use std::vector than new/delete, *especially* when you're new to C++. – Petter Dec 22 '10 at 11:44
4

In reference to your follow-on question:

The best reference I have used for general high-level programming "current good practices" sort of thing is:

Code Complete by Steve McConnell (ISBN 0-7356-1967-0)

I reference it all the time. When my company formalized its coding standards, I wrote them based off of it. It doesn't go into design or architecture as much, but for actually banging out code, the book is appropriately named.

Nate
  • 12,499
  • 5
  • 45
  • 60
  • The end of the question says: "Also if anyone has references of where I can find best practices for this kind of stuff it would be helpful? Kind of an etiquette for programmers book." This is what I provided. I didn't realize that we were supposed to stick to the title of the question, and not stray to answering follow-on questions. – Nate Oct 27 '10 at 16:02
2

cudaMalloc takes a size of type size_t, so for consistency, that's what you should use for indices.

Steve M
  • 8,246
  • 2
  • 25
  • 26
-1

Well, since you've already abandoned best practice, even GOOD practice, by using malloc...why does it really matter?

That said, I generally use size_t unless I need a type that can go negative for various semi-rare conditions.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
-1

I would prefer int over size_t for a couple reasons:

  1. primitive types should be preferred unless the typedef provides something fundamentally new, size_t here doesn't
  2. the size_t is defined differently on different systems, possibly creating surprises for some developers
  3. signed int avoids for (size_t i=9; i>=0; --i) bugs, as well as other bugs in conditionals, e.g. if (result < 1) or if ((i-2)/2 < 1)

size_t is a useless abstraction that masks undesired behavior by silencing underflows

Inverse
  • 4,408
  • 2
  • 26
  • 35
  • 2
    1. `size_t` is a standardized typedef for a primitive type. 2. `int` also varies from system to system. 3. A good compiler will warn you when you say `i >= 0` for an unsigned type. `int` masks undesired behavior by silencing overflows. – Adrian McCarthy Oct 27 '10 at 17:58
  • 1
    I've arrived here to argue 12 years later! I agree very much with point 3 here ^. How do you iterate backwards with size_t ? If the index is size_t, and its 0, 0--, becomes LONG_MAX. – CraigDavid Jul 13 '22 at 17:38