AnyClass

Discussion in 'C++' started by JKop, Oct 12, 2004.

  1. JKop

    JKop Guest

    I've written two files:

    anyclass.cpp
    anyclass.hpp


    Within is the definition of the class "AnyClass". It's used for testing
    purposes and for playing around, having some fun.

    What the class does is (optionally) print text whenever an object of it is
    created, destroyed, assigned to.

    The constructor works as so:

    AnyClass blah("blah");


    You supply it with a name. This name will be copied into its internal
    storage. All text which is printed will refer to the object by name. If you
    do the following:

    AnyClass poo = blah;

    Then the object "poo" will have the name "Copy of blah".


    Here's its public members:

    object_counter : a static read-only variable of type "unsigned" which holds
    the amount of objects of "AnyClass" currently in existence.

    GetName() : returns a pointer to the string which contains the name of the
    object.

    to_play_with : just a non-const member variable of type "unsigned" to play
    around with.


    Here's an example usage:


    #include "anyclass.hpp"

    int main()
    {
    AnyClass const &blah = AnyClass("no-name");

    std::cout << "\nHaHa\n";
    }


    This program will output the following:

    AnyClass Constructor for: no-name

    HaHa
    AnyClass Destructor for: no-name


    Which shows that the temporary in the above is valid until the end of the
    function.

    If you don't want the class to print out at all, then do the following:

    #define ANYCLASS_NO_OUTPUT
    #include "anyclass.hpp"


    but unfortunately you'll also have to edit the ".cpp" file also to achieve
    this.


    Here it is. . .

    //anyclass.hpp

    #ifndef INCLUDE_ANYCLASS_HPP
    #define INCLUDE_ANYCLASS_HPP

    #ifndef ANYCLASS_NO_OUTPUT
    #include <iostream>
    #endif

    #include <cstddef>
    #include <cstring>

    class AnyClass
    {
    public:

    static unsigned const &object_counter;

    unsigned to_play_with;


    const char* GetName() const
    {
    return name;
    }


    private:

    static unsigned object_counter_prv;
    char* name;

    public:

    AnyClass(const char* const in_name, unsigned const in_to_play_with = 0)
    : to_play_with(in_to_play_with)
    {

    std::size_t length = std::strlen( in_name );

    name = new char[length += 1];

    memcpy(name, in_name, length);

    ++object_counter_prv;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Constructor for: " << name <<
    '\n';
    #endif

    }


    AnyClass(AnyClass const &original) : to_play_with
    (original.to_play_with)
    {
    std::size_t length = std::strlen( original.name );

    name = new char[length += 9]; //9 = 8 + 1 (1 for the null
    character)

    memcpy( name, "Copy of " , 8 ); // . . .waste of a null
    character

    memcpy( &name[8], original.name, length -= 9 ); //Take the 9
    back off

    name[length += 8] = '\0';

    ++object_counter_prv;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << "AnyClass Copy Constructor for: " << name << '\n';
    #endif
    }

    AnyClass& operator=(AnyClass const &other)
    {
    //NB: There is no name change whatsoever

    to_play_with = other.to_play_with;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Assignment Operator: " << name << "
    = " << other.name << '\n';
    #endif

    return *this;
    }

    ~AnyClass()
    {
    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Destructor for: " << name <<
    '\n';
    #endif

    delete [] name;
    --object_counter_prv;
    }
    };


    #endif



    //anyclass.cpp

    #include "anyclass.hpp"

    unsigned AnyClass::eek:bject_counter_prv = 0;
    unsigned const &AnyClass::eek:bject_counter = AnyClass::eek:bject_counter_prv;




    Any comments, questions, suggestions welcomed.


    -JKop
    JKop, Oct 12, 2004
    #1
    1. Advertising

  2. JKop

    David Harmon Guest

    On Tue, 12 Oct 2004 13:34:44 GMT in comp.lang.c++, JKop <>
    wrote,
    > std::size_t length = std::strlen( original.name );
    >
    > name = new char[length += 9]; //9 = 8 + 1 (1 for the null
    >character)
    >
    > memcpy( name, "Copy of " , 8 ); // . . .waste of a null
    >character
    >
    > memcpy( &name[8], original.name, length -= 9 ); //Take the 9
    >back off


    In my opinion, you should use std::string and omit all that error-prone
    char* hacking.
    David Harmon, Oct 12, 2004
    #2
    1. Advertising

  3. JKop

    JKop Guest

    David Harmon posted:

    > On Tue, 12 Oct 2004 13:34:44 GMT in comp.lang.c++, JKop
    > <> wrote,
    >> std::size_t length = std::strlen( original.name );
    >>
    >> name = new char[length += 9]; //9 = 8 + 1 (1 for the
    >> null character)
    >>
    >> memcpy( name, "Copy of " , 8 ); // . . .waste of a null
    >> character
    >>
    >> memcpy( &name[8], original.name, length -= 9 ); //Take
    >> the 9 back off

    >
    > In my opinion, you should use std::string and omit all that error-prone
    > char* hacking.


    I strongly disagree.

    There is nothing error-prone about the above, nor is there any "hacking".
    It's just good ol' C++.

    In my own opinion, it's a disgrace to use "std::string" and the like for
    simple uses like the above. Does no-one believe in efficiency anymore?

    I will although admit that it takes a bit of thinking to make sure you put
    in the right array indexes, eg. "&name[8]", but I actually enjoy that and I
    end up with much more efficient code.

    I'll say that there are however great uses for "std::string". I use in when
    I'm doing *extreme* string manipulation, especially where I would have to
    resize the buffer were I to do it myself. In the cases, it's preferrable to
    use simple "std::string" members than to spend an hour messing with chars.


    -JKop
    JKop, Oct 13, 2004
    #3
  4. JKop

    Jerry Coffin Guest

    JKop <> wrote in message news:<Df5bd.33286$>...
    > David Harmon posted:


    [ ... ]

    > > In my opinion, you should use std::string and omit all that error-prone
    > > char* hacking.

    >
    > I strongly disagree.
    >
    > There is nothing error-prone about the above, nor is there any "hacking".
    > It's just good ol' C++.
    >
    > In my own opinion, it's a disgrace to use "std::string" and the like for
    > simple uses like the above. Does no-one believe in efficiency anymore?


    Quite a few of us do -- and we realize (for example) that doing the
    job with std::string will often be substantially MORE efficient than
    using C string functions.

    Just for example, your code contains a call to strlen, which is an
    O(N) function since it has to search through the entire string to find
    the end. By contrast, an std::string object normally stores the
    current length as a member, meaning that std::string::length() is a
    trivial O(1) function.

    As such, your code's speed depends (heavily) on the length of
    original.name. An implementation using std::string instead can remove
    this depency, and retain essentially the same (or better) efficiency
    in other areas as well. There will inevitably be a length of
    original.name beyond which std::string is more efficient than your
    code -- and that length may easily be 0.

    > I will although admit that it takes a bit of thinking to make sure you put
    > in the right array indexes, eg. "&name[8]", but I actually enjoy that and I
    > end up with much more efficient code.


    The name for that kind of code is "fragile." If you insist on writing
    something like this, a bare minimum of decency would be code something
    like:

    static char cpy[] = "Copy of ";
    static size_t len = sizeof(cpy);

    memcpy(name, cpy, len-1);
    memcpy(name+len-1, original.name, length-=len);

    This way, you don't have a "magic" number like 8 in the code, instead
    using a value whose derivation is obvious. Better still, if (for
    example) somebody decided to translate the code to their choice of
    languages other than English, where "copy of" would almost certainly
    be a different size, the size would automatically change with the
    change in string length.

    IMO, all of this remains essentially pointless: given a halfway
    reasonable implementation of the standard library, I'd expect
    std::string to be right in the same general ballpark for speed as
    doing this manually. To test this theory, I created a modified version
    of your class using std::string:

    //anyclass.hpp

    #ifndef INCLUDE_ANYCLASS_HPP
    #define INCLUDE_ANYCLASS_HPP

    #ifndef ANYCLASS_NO_OUTPUT
    #include <iostream>
    #endif

    #include <string>

    class AnyClass
    {
    public:
    static unsigned const &object_counter;

    unsigned to_play_with;

    std::string const &GetName() const
    {
    return name;
    }


    private:

    static unsigned object_counter_prv;
    std::string name;

    public:

    AnyClass(std::string const &in_name, unsigned in_to_play_with =
    0)
    : to_play_with(in_to_play_with), name(in_name)
    {
    ++object_counter_prv;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Constructor for: " << name <<
    '\n';
    #endif

    }


    AnyClass(AnyClass const &original) :
    to_play_with(original.to_play_with)
    {
    name = std::string("Copy of ") + original.name;
    ++object_counter_prv;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << "AnyClass Copy Constructor for: " << name <<
    '\n';
    #endif
    }

    AnyClass& operator=(AnyClass const &other)
    {
    //NB: There is no name change whatsoever

    to_play_with = other.to_play_with;

    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Assignment Operator: " <<
    name << " = " << other.name << '\n';
    #endif

    return *this;
    }

    ~AnyClass()
    {
    #ifndef ANYCLASS_NO_OUTPUT
    std::cout << " AnyClass Destructor for: " << name <<
    '\n';
    #endif
    --object_counter_prv;
    }
    };

    #endif

    and then I whipped together a quick test harness:

    #define ANYCLASS_NO_OUTPUT

    #include <time.h>

    #ifdef USESTRING
    #include "anyclass.hpp"
    #else
    #include "anyclass1.hpp"
    #endif

    #include <iostream>
    int main() {

    const int num = 5000;

    AnyClass *x[num];

    clock_t start = clock();
    x[0] = new AnyClass("X");
    for (int i=1; i<num; i++)
    x = new AnyClass(*x[i-1]);
    clock_t overall = clock()-start;

    #ifdef USESTRING
    std::cout << "length: " << x[num-1]->GetName().length();
    #else
    std::cout << "length: " << strlen(x[num-1]->GetName());
    #endif

    std::cout << "\nTime: " << overall/(double)CLOCKS_PER_SEC <<
    " seconds\n";
    return 0;
    }

    I compiled the code with VC++ 7.1 using:

    cl /O2b2 /G7ry any.cpp anyclass.cpp

    and:

    cl /DUSESTRING /O2b2 /G7ry any.cpp anyclass.cpp

    and ran both versions. On my particular machine, both versions claimed
    to run in .312 seconds. It's possible (probable, in reality) that if
    you ran them often enough that you'd at least ocassionally see a
    difference in speed (on the order of a single clock tick worth, I'd
    guess). With a lot of runs and careful statistical analysis, you might
    even even find a statistically significant difference between them --
    but without more testing, it's hard to even guess which one would be
    likely to win -- std::string might be about as likely to be faster as
    slower. In any case, I think that's more or less irrelevant: there's
    no real room for question that the code using std::string is a LOT
    simpler, and the code using raw char *'s clearly is not a LOT faster,
    which is what would be needed to justify its own existence.

    I'd also note that using raw pointers makes exception safety
    considerably more difficult to provide.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Oct 13, 2004
    #4
  5. JKop

    JKop Guest

    Jerry Coffin posted:

    > JKop <> wrote in message
    > news:<Df5bd.33286$>...
    >> David Harmon posted:

    >
    > [ ... ]
    >
    >> > In my opinion, you should use std::string and omit all that
    >> > error-prone char* hacking.

    >>
    >> I strongly disagree.
    >>
    >> There is nothing error-prone about the above, nor is there any
    >> "hacking". It's just good ol' C++.
    >>
    >> In my own opinion, it's a disgrace to use "std::string" and the like
    >> for simple uses like the above. Does no-one believe in efficiency
    >> anymore?

    >
    > Quite a few of us do -- and we realize (for example) that doing the
    > job with std::string will often be substantially MORE efficient than
    > using C string functions.
    >
    > Just for example, your code contains a call to strlen, which is an
    > O(N) function since it has to search through the entire string to find
    > the end. By contrast, an std::string object normally stores the
    > current length as a member, meaning that std::string::length() is a
    > trivial O(1) function.
    >
    > As such, your code's speed depends (heavily) on the length of
    > original.name. An implementation using std::string instead can remove
    > this depency, and retain essentially the same (or better) efficiency
    > in other areas as well. There will inevitably be a length of
    > original.name beyond which std::string is more efficient than your
    > code -- and that length may easily be 0.
    >
    >> I will although admit that it takes a bit of thinking to make sure you
    >> put in the right array indexes, eg. "&name[8]", but I actually enjoy
    >> that and I end up with much more efficient code.

    >
    > The name for that kind of code is "fragile." If you insist on writing
    > something like this, a bare minimum of decency would be code something
    > like:
    >
    > static char cpy[] = "Copy of ";
    > static size_t len = sizeof(cpy);
    >
    > memcpy(name, cpy, len-1);
    > memcpy(name+len-1, original.name, length-=len);
    >
    > This way, you don't have a "magic" number like 8 in the code, instead
    > using a value whose derivation is obvious. Better still, if (for
    > example) somebody decided to translate the code to their choice of
    > languages other than English, where "copy of" would almost certainly
    > be a different size, the size would automatically change with the
    > change in string length.
    >
    > IMO, all of this remains essentially pointless: given a halfway
    > reasonable implementation of the standard library, I'd expect
    > std::string to be right in the same general ballpark for speed as
    > doing this manually. To test this theory, I created a modified version
    > of your class using std::string:
    >
    > //anyclass.hpp
    >
    > #ifndef INCLUDE_ANYCLASS_HPP
    > #define INCLUDE_ANYCLASS_HPP
    >
    > #ifndef ANYCLASS_NO_OUTPUT
    > #include <iostream>
    > #endif
    >
    > #include <string>
    >
    > class AnyClass
    > {
    > public:
    > static unsigned const &object_counter;
    >
    > unsigned to_play_with;
    >
    > std::string const &GetName() const
    > {
    > return name;
    > }
    >
    >
    > private:
    >
    > static unsigned object_counter_prv;
    > std::string name;
    >
    > public:
    >
    > AnyClass(std::string const &in_name, unsigned in_to_play_with =
    > 0)
    > : to_play_with(in_to_play_with), name(in_name)
    > {
    > ++object_counter_prv;
    >
    > #ifndef ANYCLASS_NO_OUTPUT
    > std::cout << " AnyClass Constructor for: " << name <<
    > '\n';
    > #endif
    >
    > }
    >
    >
    > AnyClass(AnyClass const &original) :
    > to_play_with(original.to_play_with)
    > {
    > name = std::string("Copy of ") + original.name;
    > ++object_counter_prv;
    >
    > #ifndef ANYCLASS_NO_OUTPUT
    > std::cout << "AnyClass Copy Constructor for: " << name <<
    > '\n';
    > #endif
    > }
    >
    > AnyClass& operator=(AnyClass const &other)
    > {
    > //NB: There is no name change whatsoever
    >
    > to_play_with = other.to_play_with;
    >
    > #ifndef ANYCLASS_NO_OUTPUT
    > std::cout << " AnyClass Assignment Operator: " <<
    > name << " = " << other.name << '\n';
    > #endif
    >
    > return *this;
    > }
    >
    > ~AnyClass()
    > {
    > #ifndef ANYCLASS_NO_OUTPUT
    > std::cout << " AnyClass Destructor for: " << name <<
    > '\n';
    > #endif
    > --object_counter_prv;
    > }
    > };
    >
    > #endif
    >
    > and then I whipped together a quick test harness:
    >
    > #define ANYCLASS_NO_OUTPUT
    >
    > #include <time.h>
    >
    > #ifdef USESTRING
    > #include "anyclass.hpp"
    > #else
    > #include "anyclass1.hpp"
    > #endif
    >
    > #include <iostream>
    > int main() {
    >
    > const int num = 5000;
    >
    > AnyClass *x[num];
    >
    > clock_t start = clock();
    > x[0] = new AnyClass("X");
    > for (int i=1; i<num; i++)
    > x = new AnyClass(*x[i-1]);
    > clock_t overall = clock()-start;
    >
    > #ifdef USESTRING
    > std::cout << "length: " << x[num-1]->GetName().length();
    > #else
    > std::cout << "length: " << strlen(x[num-1]->GetName());
    > #endif
    >
    > std::cout << "\nTime: " << overall/(double)CLOCKS_PER_SEC <<
    > " seconds\n";
    > return 0;
    > }
    >
    > I compiled the code with VC++ 7.1 using:
    >
    > cl /O2b2 /G7ry any.cpp anyclass.cpp
    >
    > and:
    >
    > cl /DUSESTRING /O2b2 /G7ry any.cpp anyclass.cpp
    >
    > and ran both versions. On my particular machine, both versions claimed
    > to run in .312 seconds. It's possible (probable, in reality) that if
    > you ran them often enough that you'd at least ocassionally see a
    > difference in speed (on the order of a single clock tick worth, I'd
    > guess). With a lot of runs and careful statistical analysis, you might
    > even even find a statistically significant difference between them --
    > but without more testing, it's hard to even guess which one would be
    > likely to win -- std::string might be about as likely to be faster as
    > slower. In any case, I think that's more or less irrelevant: there's
    > no real room for question that the code using std::string is a LOT
    > simpler, and the code using raw char *'s clearly is not a LOT faster,
    > which is what would be needed to justify its own existence.
    >
    > I'd also note that using raw pointers makes exception safety
    > considerably more difficult to provide.



    I think this newsgroup has the best community of all I've been to!

    Thanks for working all that out, Gerry.


    You know that template "getcount" (or something like that) that tells you
    the length of an array... well I found another use for it:

    getcount("Copy of ");


    :-D



    -JKop
    JKop, Oct 13, 2004
    #5
  6. JKop

    Jerry Coffin Guest

    JKop <> wrote in message news:<3Lgbd.33354$>...

    [ ... ]

    > Thanks for working all that out, Gerry.


    You're certainly welcome, but my name is Jerry.

    > You know that template "getcount" (or something like that) that tells you
    > the length of an array... well I found another use for it:
    >
    > getcount("Copy of ");


    Actually, if you insist on using memcpy (or memmove, etc.) that's
    _not_ what you really want. The argument to memcpy specifies a number
    of _bytes_ to move, _not_ the number of elements.

    In this particular case, with a string of char's, the two will be the
    same because the C and C++ standards specify sizeof(char) is always 1.

    Using the number of elements will lead to a problem, however, if the
    type of string changes -- the obvious choice being to change it to
    something like:

    wchar_t cpy[] = L"Copy of";

    in which case using sizeof still yields the correct size, but using
    the number of elements will typically yield one half or one quarter
    the correct size.

    The bottom line is pretty simple: memcpy works in bytes, so you need
    to specify its arguments in bytes. You'd use the number of elements if
    you were using a function (or template) that works in the number of
    elements, such as some in the C++ standard libary (e.g. std::fill_n --
    std::copy uses iterators to specify the starting and ending points).

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Oct 14, 2004
    #6
  7. JKop

    JKop Guest

    Jerry Coffin posted:

    > JKop <> wrote in message
    > news:<3Lgbd.33354$>...
    >
    > [ ... ]
    >
    >> Thanks for working all that out, Gerry.

    >
    > You're certainly welcome, but my name is Jerry.



    Sorry about that, force of habit (I live in Ireland and it's spelled
    "Gerry" over here).


    >> You know that template "getcount" (or something like that) that tells
    >> you the length of an array... well I found another use for it:
    >>
    >> getcount("Copy of ");

    >
    > Actually, if you insist on using memcpy (or memmove, etc.) that's
    > _not_ what you really want. The argument to memcpy specifies a number
    > of _bytes_ to move, _not_ the number of elements.
    >
    > In this particular case, with a string of char's, the two will be the
    > same because the C and C++ standards specify sizeof(char) is always 1.
    >
    > Using the number of elements will lead to a problem, however, if the
    > type of string changes -- the obvious choice being to change it to
    > something like:
    >
    > wchar_t cpy[] = L"Copy of";
    >
    > in which case using sizeof still yields the correct size, but using
    > the number of elements will typically yield one half or one quarter
    > the correct size.
    >
    > The bottom line is pretty simple: memcpy works in bytes, so you need
    > to specify its arguments in bytes. You'd use the number of elements if
    > you were using a function (or template) that works in the number of
    > elements, such as some in the C++ standard libary (e.g. std::fill_n --
    > std::copy uses iterators to specify the starting and ending points).


    memcpy( y, x, getcount(array) * sizeof(array[0]) );


    -JKop
    JKop, Oct 14, 2004
    #7
  8. JKop

    David Rubin Guest

    (Jerry Coffin) wrote in message news:<>...
    > JKop <> wrote in message news:<Df5bd.33286$>...
    > > David Harmon posted:



    [snip]

    Given some version of class 'AnyClass' with a contructor like

    AnyClass(const std::string& name, unsigned value = 0);
    or
    AnyClass(const char *name, unsigned value = 0);

    ....

    > and then I whipped together a quick test harness:
    >
    > #define ANYCLASS_NO_OUTPUT
    >
    > #include <time.h>
    >
    > #ifdef USESTRING
    > #include "anyclass.hpp"
    > #else
    > #include "anyclass1.hpp"
    > #endif
    >
    > #include <iostream>
    > int main() {
    >
    > const int num = 5000;
    >
    > AnyClass *x[num];
    >
    > clock_t start = clock();
    > x[0] = new AnyClass("X");
    > for (int i=1; i<num; i++)
    > x = new AnyClass(*x[i-1]);
    > clock_t overall = clock()-start;
    >
    > #ifdef USESTRING
    > std::cout << "length: " << x[num-1]->GetName().length();
    > #else
    > std::cout << "length: " << strlen(x[num-1]->GetName());
    > #endif
    >
    > std::cout << "\nTime: " << overall/(double)CLOCKS_PER_SEC <<
    > " seconds\n";
    > return 0;
    > }
    >
    > I compiled the code with VC++ 7.1 using:
    >
    > cl /O2b2 /G7ry any.cpp anyclass.cpp
    >
    > and:
    >
    > cl /DUSESTRING /O2b2 /G7ry any.cpp anyclass.cpp
    >
    > and ran both versions. On my particular machine, both versions claimed
    > to run in .312 seconds. It's possible (probable, in reality) that if
    > you ran them often enough that you'd at least ocassionally see a
    > difference in speed (on the order of a single clock tick worth, I'd
    > guess). With a lot of runs and careful statistical analysis, you might
    > even even find a statistically significant difference between them --
    > but without more testing, it's hard to even guess which one would be
    > likely to win -- std::string might be about as likely to be faster as
    > slower. In any case, I think that's more or less irrelevant: there's
    > no real room for question that the code using std::string is a LOT
    > simpler, and the code using raw char *'s clearly is not a LOT faster,
    > which is what would be needed to justify its own existence.


    What you want to do is something more like this:

    enum {
    NUM_ITERATIONS = 5000,
    GROW_LENGTH = 131
    };
    int length = GROW_LENGTH;
    AnyClass x("");
    for (int i = 0; i < NUM_ITERATIONS; ++i) {
    std::string name(length, '#');
    const char *NAME = name.c_str();

    clock_t start = std::clock();
    #ifdef USESTRING
    AnyClass a(name);
    #else
    AnyClass a(NAME);
    #endif
    AnyClass b(a);
    x = a;
    clock_t totalTime = std::clock() - start;
    std::cout << "length = " << length << ", "
    << "time = " << totalTime
    << std::endl;
    length += GROW_LENGTH;
    }

    Perhaps you will see some more deviation in the results. /david
    David Rubin, Oct 15, 2004
    #8
  9. JKop

    Jerry Coffin Guest

    JKop <> wrote in message news:<0Cxbd.33431$>...

    [ ... ]

    > > The bottom line is pretty simple: memcpy works in bytes, so you need
    > > to specify its arguments in bytes. You'd use the number of elements if
    > > you were using a function (or template) that works in the number of
    > > elements, such as some in the C++ standard libary (e.g. std::fill_n --
    > > std::copy uses iterators to specify the starting and ending points).

    >
    > memcpy( y, x, getcount(array) * sizeof(array[0]) );


    IMO, this is just a roundabout way of getting back to where we started
    -- getcount is normally defined something like:

    #define getcount(array) (sizeof(array)/sizeof(array[0]))

    So you're doing:

    sizeof(array)/sizeof(array[0]) * sizeof(array[0])

    and the sizeof(array[0])'s cancel, giving sizeof(array).

    The bottom line is that if you intend to copy the entire array, you
    might as well just specify "sizeof(array)" and be done with it.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Oct 15, 2004
    #9
  10. JKop

    JKop Guest


    > #define getcount(array) (sizeof(array)/sizeof(array[0]))



    #include <cstddef>

    template<class T, std::size_t amount_elements>
    inline std::size_t getcount( T (&array)[amount_elements] )
    {
    return amount_elements;
    }


    -JKop
    JKop, Oct 15, 2004
    #10
  11. In message <>, Jerry
    Coffin <> writes
    >JKop <> wrote in message
    >news:<0Cxbd.33431$>...
    >
    >[ ... ]
    >
    >> > The bottom line is pretty simple: memcpy works in bytes, so you need
    >> > to specify its arguments in bytes. You'd use the number of elements if
    >> > you were using a function (or template) that works in the number of
    >> > elements, such as some in the C++ standard libary (e.g. std::fill_n --
    >> > std::copy uses iterators to specify the starting and ending points).

    >>
    >> memcpy( y, x, getcount(array) * sizeof(array[0]) );

    >
    >IMO, this is just a roundabout way of getting back to where we started
    >-- getcount is normally defined something like:
    >
    >#define getcount(array) (sizeof(array)/sizeof(array[0]))
    >
    >So you're doing:
    >
    >sizeof(array)/sizeof(array[0]) * sizeof(array[0])
    >
    >and the sizeof(array[0])'s cancel, giving sizeof(array).
    >
    >The bottom line is that if you intend to copy the entire array, you
    >might as well just specify "sizeof(array)" and be done with it.
    >

    Except that if getcount() is a template function rather than a macro,
    you can use template techniques to check that its argument really is an
    array and not something that's accidentally decayed to a pointer.

    --
    Richard Herring
    Richard Herring, Oct 18, 2004
    #11
  12. JKop

    JKop Guest


    > Except that if getcount() is a template function rather than a macro,
    > you can use template techniques to check that its argument really is an
    > array and not something that's accidentally decayed to a pointer.



    I like!


    -JKop
    JKop, Oct 18, 2004
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page