1

I am trying to create custom array indexed from 1 using subscript operator. Getting value works fine, but I have no clue, why assign using subscript operator doesn't work.

class CEntry {
public:
  CKey key;
  CValue val;

  CEntry(const CKey& key, const CValue& val) {
    this->key = key;
    this->val = val;
  }

  CEntry& operator= (const CEntry& b) {
    *this = b;
    return *this;
  };
};

...

class EntriesArray {    
public:
    CEntry **entries;
    int length;

  EntriesArray(int length) {
    this->length = length;
    entries = new CEntry*[length];
    int i;
    for (i = 0; i < length + 1; i++) {
        entries[i] = NULL;
    }
  };

  CEntry& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw ArrayOutOfBounds();
      }
      return *entries[index - 1];
  };

};

Constructs array this way

EntriesArray a(5);

This works

 a.entries[0] = new CEntry(CKey(1), CValue(1));
 cout << a[1].val.value << endl;

This doesn't work

a[1] = new CEntry(CKey(1), CValue(1));

EDIT:

Using

CEntry *operator=( CEntry *orig)

it compiles okey, but gdb stops at

No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame

with backtrace

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x00000001000013c8 in CEntry::operator= (this=0x0, orig=0x1001008d0) at /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp:20
20  /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp: No such file or directory.
in /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp
1
  • XCode says: No viable overloaded '=' Commented Jan 31, 2012 at 0:28

6 Answers 6

2

At first... This:

CEntry& operator= (const CEntry& b) {
    *this = b;
    return *this;
};

Shouldn't work (this should result in recursive call of operator=).

The second thing is that you're trying to assign CEntry * to CEntry, this would work if you had CEntry *operator=( CEntry *orig), but I think this is bad coding practice.

Sign up to request clarification or add additional context in comments.

7 Comments

Using CEntry *operator=( CEntry *orig) it compiles okey, but gdb stops at No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame
@sealskej add this warning to your question and add output of bt (backtrace) command from gdb after fall (I hope you're using -g flag when compiling).
Thanks for your help. I added bt to my post as you have suggested.
@sealskej I still don't see bt output, it should be something like: #0 XS::ModuleLoader::i () at include/ModuleLoader.h:35 #1 0x000000000040e483 in main (argc=1, argv=0x7fffffffe628) at src/main.cpp:37
@sealskej if you have console available you should be able to run: gdb yourApp than type run (inside gdb) and when application falls than bt :)
|
1

This question may be related to this one.

I tried to fix your code; I believe that this is what you were trying to do:

(tested this code on g++ 5.3.0)

#include <iostream>
#include <stdexcept>
#include <string>

// Some implementation for CKey and CValue:
typedef int CKey;
struct CValue {
  int value;
  CValue(int value=0) : value(value) {}
};

class CEntry {
public:
  CKey key;
  CValue val;

  CEntry(): key(0), val(0) {}
  CEntry(const CKey& key, const CValue& val): key(key), val(val) {}

  CEntry& operator= (const CEntry& b) {
    this->key = b.key;
    this->val = b.val;
    return *this;
  };
};

class EntriesArray {    
public:
    CEntry *entries;
    int length;

  EntriesArray(int length) {
    this->length = length;
    entries = new CEntry[length];
  };

  CEntry& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw std::domain_error("out of bounds!");
      }
      return entries[index - 1];
  };

};

int main(int argc, char* argv[]) {
  using namespace std;

  EntriesArray a(5);

  // This works
  a.entries[0] = CEntry(CKey(1), CValue(1));
  cout << a[1].val.value << endl;

  // This doesn't work
  a[1] = CEntry(CKey(2), CValue(2));
  cout << a[1].val.value << endl;
}

Also you might want to use a[1] as a[1].val.value e.g.:

cout << a[1] << endl;

To do this just add to this line to cEntry:

operator int() { return val.value; }

I hope it helps.

Comments

0

You could try replacing

CEntry& operator[] (const int index) {
    if (index < 1 || index > length) {
        throw ArrayOutOfBounds();
    }
    return *entries[index - 1];
};

with

void Add(const int index, CEntry *pEntry) {
    if (index < 1 || index > length) {
        throw ArrayOutOfBounds();
    }
    entries[index - 1] = pEntry;
};

but since you are now storing references to objects allocated on the heap (with new) you will need a destructor ~EntriesArray() to delete them all.

2 Comments

Yeah, this could be solution, but I would have to create getter as well, I guess.
I was expecting a way to do it like the std::vector class does, e.g.: myVec[10]=value; None of the available answers explained that. Is it not possible?
0

Because EntriesArray::operator[] returns a CEntry &, but new CEntry returns a CEntry *.

Perhaps you want a[1] = CEntry(CKey(1), CValue(1))? (no new.)


By the way, your current definition of CEntry::operator= will lead to a stack overflow.

4 Comments

I have tried to return CEntry* in EntriesArray::operator[]. Seems not working as well :( Could you please post example, how to solve it?
@sealskej: Don't have it return a CEntry *, that would lead to ugly semantics.
This is true, but I think it'll still fail even when this is fixed. When you do a[1], 1 is > length so you'll get an ArrayOutOfBounds.
@John3136: We haven't seen how a has been constructed.
0

This

return *entries[index - 1];

dereferences a NULL pointer.

You want the pointer itself to be overwritten by a[1] = new CEntry(CKey(1), CValue(1));, not the pointed-to-value.

Try this:

class EntriesArray
{    
public:
  int length;
  CEntry **entries;

  EntriesArray( int length ) : length(length), entries(new CEntry*[length]())
  {
  }

  // defaulted special member functions are inappropriate for this class
  EntriesArray( const EntriesArray& );          // need custom copy-constructor
 ~EntriesArray();                               // need custom destructor
  EntriesArray& operator=(const EntriesArray&); // need custom assignment-operator

  CEntry*& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw ArrayOutOfBounds();
      }
      return entries[index - 1];
  }
};

4 Comments

I have tried this, but I am getting same backtrace mentioned in EDIT part of my post. Using CEntry *operator=( CEntry *orig).
@sealskej: Get rid of CEntry's assignment operator, the compiler-generated one should be fine. And then try this code.
When I get rid of CEntry's assignment operator, I am getting No viable overloaded '=' by XCode on line a[1] = new CEntry(CKey(1), CValue(1));
@sealskej: Line 164 and 168 are not the same as what I gave you.
0

Further to my comment above: To make it work with writing new values, you probably need something like this (I haven't double checked for off by one or ptr vs reference stuff)

CEntry& operator[] (const int index) {
  if (index < 1) {
      throw ArrayOutOfBounds();
  }
  // Add default elements between the current end of the list and the
  // non existent entry we just selected.
  //
  for(int i = length; i < index; i++)
  {
      // BUG is here.
      // We don't actually know how "entries" was allocated, so we can't
      // assume we can just add to it.
      // We'd need to try to resize entries before coming into this loop.
      // (anyone remember realloc()? ;-)
      entries[i] = new CEntry();
  }
  return *entries[index - 1];
};

6 Comments

No, this will just happily write past the end of the entries array and trash other objects' memory.
Yes, you are 100% correct. Stupid stupid stupid stupid. Allocated the objects, but didn't increase the array size to include them. Makes me think if what the OP wants is a random access 1 base array, might be better to wrap a vector or something.
I definitely agree. But everyone has to rewrite std::vector at least once so they properly appreciate it.
I cant use std::vector, because I am doing school homework, where it is forbidden.
Maybe I will use John's solution, but overloaded subscript operator seemed more elegant for me. I need to create 1 base array, because I want to rewrite b-tree operations pseudocode, which uses 1 base array.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.