Arrays of dynamic objects and operator[]

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Andrew.Morgan@telkomsa.net

    Arrays of dynamic objects and operator[]

    Hi

    I have three classes TDigest, THash and TSHA1.

    //---------------------------------------------------------------------------
    class TDigest
    {
    public:
    // Constructors.
    TDigest(int Count);
    TDigest(const TDigest &Source);

    // Destructors.
    ~TDigest();

    // Operators.
    TDigest& operator=(const TDigest &Source);
    unsigned char& operator[](const int Index);

    // Functions.
    int Count();

    private:
    int count;
    unsigned char *v,illegal;
    };

    TDigest has a variable length dynamic array, and is the return type of
    THash::Digest() and its descendants. The operator[] provides
    access to the individual bytes that make up the hash.

    //---------------------------------------------------------------------------
    class THash
    {
    public:
    // Constructors.
    THash();
    THash(const THash &Source);

    // Destructors.
    virtual ~THash();

    // Operators.
    THash& operator=(const THash &Source);

    // Functions.
    virtual void Init(unsigned int Count);
    virtual void Block(char* Block);
    virtual TDigest Digest();

    protected:
    unsigned int count;
    virtual void Process();
    };

    THash is the base class for implementing a family of hash algorithms.

    //---------------------------------------------------------------------------
    class TSHA1:public THash
    {
    public:
    // Constructors.
    TSHA1();
    TSHA1(const TSHA1 &Source);

    // Destructors.
    ~TSHA1();

    // Operators.
    TSHA1& operator=(const TSHA1 &Source);

    // Functions.
    void Init(unsigned int Count);
    void Block(char* Block);
    TDigest Digest();

    protected:
    unsigned int blocks,expand[80],work[5],hash[5],round[4];
    void Process();
    };

    TSHA1 produces the SHA-1 hash for the supplied blocks of data.

    My dilemma begins when trying to return the digest.

    The following works, but has the overhead of temporaries with
    associated constructor and destructor calls.

    TDigest THash::Digest()
    {
    TDigest digest(20); // setup 160-bit digest.
    int index = 0;
    for...
    for...
    digest[index++] = ...
    return digest;
    }

    What I would prefer to do is:
    TDigest* THash::Digest()
    {
    TDigest digest = new TDigest(20); // setup 160-bit digest.
    int index = 0;
    for...
    for...
    digest[index++] = ...
    return digest;
    }

    However, at the digest[index++] point, how does the compiler
    distinguish between an array of TDigest objects, or the operator[] to
    access a specific byte of the digest's internal array? In this case,
    the compiler appears to assume that an array of objects has been
    created (which seems odd to me since there was no "new TDigest[count]"
    involved) and generates code to access the index-th digest object,
    which does not exist beyond 0 (digest is digest[0]).

    The following works:
    digest[0][index++] = ...
    but is non-intuitive. The non-intuitive problem persists since:
    ....
    TDigest *result = sha.Digest();
    for(int i = 0; i < result->Count(); i++)
    {
    ... = result[0][i];
    }

    Unfortunately, references do not help either, since the compiler
    errors:
    "Attempting to return a reference to a local variable 'result'"

    I had hoped that my Meyers' or Sutter's texts would shed some light on
    this, but I am still in the dark.

    Thanks in advance.

    Andrew
  • Unforgiven

    #2
    Re: Arrays of dynamic objects and operator[]

    Andrew.Morgan@t elkomsa.net wrote:[color=blue]
    > My dilemma begins when trying to return the digest.[/color]
    [color=blue]
    > What I would prefer to do is:
    > TDigest* THash::Digest()
    > {
    > TDigest* digest = new TDigest(20); // setup 160-bit digest.
    > int index = 0;
    > for...
    > for...
    > digest[index++] = ...
    > return digest;
    > }
    >
    > However, at the digest[index++] point, how does the compiler
    > distinguish between an array of TDigest objects, or the operator[] to
    > access a specific byte of the digest's internal array?[/color]

    What's important here is how the compiler views digest. It is, first and
    foremost, a pointer. That it's a pointer to a TDigest is not really
    important to the compiler (in this scenario). For a TDigest object, it would
    use operator[] as defined on TDigest, but for TDigest*, it uses the
    operator[] as defined for pointers, which is memory indexing.

    As you noted, one way to get at TDigest.operato r[] is digest[0][index++],
    but that's not really natural.

    What you need to do is dereference the pointer before accessing operator[]:
    (*digest)[index++]

    It's not really elegant syntax, but it's necessary.

    --
    Unforgiven

    "Most people make generalisations "
    Freek de Jonge

    Comment

    • Andrew Morgan

      #3
      Re: Arrays of dynamic objects and operator[]

      On Thu, 2 Oct 2003 14:19:43 +0200, "Unforgiven "
      <jaapd3000@hotm ail.com> wrote:
      [color=blue]
      >Andrew.Morgan@ telkomsa.net wrote:[color=green]
      >> My dilemma begins when trying to return the digest.[/color]
      >[color=green]
      >> What I would prefer to do is:
      >> TDigest* THash::Digest()
      >> {
      >> TDigest* digest = new TDigest(20); // setup 160-bit digest.
      >> int index = 0;
      >> for...
      >> for...
      >> digest[index++] = ...
      >> return digest;
      >> }
      >>
      >> However, at the digest[index++] point, how does the compiler
      >> distinguish between an array of TDigest objects, or the operator[] to
      >> access a specific byte of the digest's internal array?[/color]
      >
      >What's important here is how the compiler views digest. It is, first and
      >foremost, a pointer. That it's a pointer to a TDigest is not really
      >important to the compiler (in this scenario). For a TDigest object, it would
      >use operator[] as defined on TDigest, but for TDigest*, it uses the
      >operator[] as defined for pointers, which is memory indexing.
      >
      >As you noted, one way to get at TDigest.operato r[] is digest[0][index++],
      >but that's not really natural.
      >
      >What you need to do is dereference the pointer before accessing operator[]:
      >(*digest)[index++]
      >
      >It's not really elegant syntax, but it's necessary.[/color]

      Thanks for the prompt reply!

      I guess I must just accept the overhead of copy constructor and
      destructor and use:

      TDigest TSHA1::Digest()
      {
      TDigest result(20);
      int pos = 0;
      for...
      for...
      result[pos++] = ...
      return result;
      }

      I did notice in the version below with dereferencing that the copy
      constructor fires (on return), but no destructor!

      TDigest& TSHA1::Digest()
      {
      TDigest *result = new TDigest(20);
      int pos = 0;
      for...
      for...
      (*result)[pos++] = ...
      return *result;
      }
      ....
      TSHA1 sha;
      ....
      TDigest digest = sha.Digest();

      digest is copy constructed from *result, but *result is not deleted? A
      memory leak?!

      This brings one to the core issue:
      When a class is the return type, how should it be constructed?

      Just a "direct" object?

      TDigest THash::Digest()
      {
      TDigest result(20);
      ....
      return result;
      }

      Comment

      • Jonathan Mcdougall

        #4
        Re: Arrays of dynamic objects and operator[]

        > class TDigest[color=blue]
        > {
        > public:
        > ...
        > unsigned char& operator[](const int Index);
        > ...
        > };[/color]
        [color=blue]
        > My dilemma begins when trying to return the digest.
        >
        > The following works, but has the overhead of temporaries with
        > associated constructor and destructor calls.
        >
        > TDigest THash::Digest()
        > {
        > TDigest digest(20); // setup 160-bit digest.
        > int index = 0;
        > for...
        > for...
        > digest[index++] = ...
        > return digest;
        > }
        >
        > What I would prefer to do is:
        > TDigest* THash::Digest()
        > {
        > TDigest digest = new TDigest(20); // setup 160-bit digest.[/color]

        Illegal

        TDigest *digest = new TDigest(20);
        [color=blue]
        > int index = 0;
        > for...
        > for...
        > digest[index++] = ...
        > return digest;
        > }
        >
        > However, at the digest[index++] point, how does the compiler
        > distinguish between an array of TDigest objects, or the operator[] to
        > access a specific byte of the digest's internal array?[/color]

        'digest' is a TDigest* and what you want is to access
        TDigest::operat or[](), no ?

        (*digest)[index++] = ...


        digest => TDigest*
        (*digest) => TDigest
        (*digest)[](x) => unsigned char&

        Don't forget to delete the digest you got somewhere.


        Jonathan


        Comment

        Working...