views:

68

answers:

6

If I have a simple class like this:

class MyClass
{
    MyClass(){}
    ~MyClass(){}
public:   
    int myArrayKeyValue;
};

And later, I create an array of these classes:

MyClass testing[10];

How, in the constructor, would I access the array key so I can set the myArrayKeyValue appropriately for each element of the array? So that I get this:

testing[0].myArrayKeyValue = 0;
testing[1].myArrayKeyValue = 1;
testing[2].myArrayKeyValue = 2;
testing[3].myArrayKeyValue = 3;
etc...

Is it possible to accomplish this in the constructor? Or do I have to just loop through the array and assign the values manually?

+3  A: 

Is it possible to accomplish this in the constructor?

No.

Or do I have to just loop through the array and assign the values manually?

Yes. Although you might be able to redesign so that you don't need the knowledge of the index inside and outside of these instances.

Possible alternatives would include:

  • an associative container like map<int, MyClass>
  • a set<MyClass> with the key value being the ordering criteria
Georg Fritzsche
A: 

You cannot do this directly from the constructor; it has no access to the object's location in the array. You will have to write a loop to do the initialization.

Alternatively -- and I'm feeling slightly disgusted at even mentioning this -- use a global or static counter that you increment from the constructor. Construction order is guaranteed to proceed from the start of the array to the end, so this will technically work. But it's horrible.

(Incidentally, the constructor in your example is private, so the array declaration wouldn't even compile.)

Thomas
A: 

Simple zero-based static member that is incremented in the constructor should do. You'd need to reset it before creating an array though. Whether this is a good idea is a completely different topic :)

Nikolai N Fetissov
That's a recipe for disaster. What if you need to perform the algorithm in two different threads concurrently?
Michael Aaron Safyan
Well, not all code is threaded. But I didn't say this is a good idea, did I? :)
Nikolai N Fetissov
What if he builds up his own OS ? Please don't vote down on solutions adapted to the information given. If it was multithreaded, he would have precised it.
Mister Mystère
The thing is the language allows you to solve this. It also allows you to shoot yourself in the ... foot. You should know better then use unprotected `static` members in threaded code. Then you should also read the question and the answer before hitting the trigger. Oh, well, kids these days :)
Nikolai N Fetissov
It's no good my reading, I can't see anywhere that it's supposed to be used in multithreading (if it's not, providing that we know it won't be, we can opt for non-protected statics)... Anyway, apparently you redeemed your down vote, so I suppose we're clear :)
Mister Mystère
A: 

You could also use a static counter as follows :

class MyClass {
    static size_t static_counter;

    size_t m_value;
public:
    MyClass() {
        m_value = static_counter++;
    }

    inline static void reset() {
        static_counter = 0;
    }

    inline size_t get_value() const {
        return m_value;
    }
};

size_t MyClass::static_counter = 0;

But you have the responsability to reset manually, or there will be memory trespassing. This would be corrected by encapsulating at higher level (reset in destructor).

Edit: I had the same idea as Nikolai N Fetissov, and to anticipate : static members as such are not to be used in multithreaded programs.

Mister Mystère
Down vote ? You surely don't encourage the others to answer with tested code.
Mister Mystère
This type of static initialization is not a good solution. Yes, it is possible, and it would work, but exactly for the reason you mention it is bad.
John Bellone
It's bad only if the program is destined to be multithreaded, and above all if we don't know what we're doing. Why vote down on a solution that clearly shows its weaknesses ? It's up to the creator of the topic to opt for it, whether it's going to be mono or multi threaded.
Mister Mystère
If it is bad programming practice for multithreading, which is becoming more common, why would you give it as an answer especially if you do not know the context of which he is attempting to use it? Static initialization is bad, plain and simple. It has its limited uses, but this is not one of them.
John Bellone
@Mister: I down-voted it for the same reason I down-voted [Nikolai's answer](http://stackoverflow.com/questions/3223917/c-get-array-key-in-constructor-of-array-of-a-custom-class-struct/3223933#3223933), where it was explained why this is a bad idea. Sorry for being to lazy to repeat that, I thought with the explanation there it was clear enough.
sbi
A: 

Something like this would be possible:

class MyClass { 
public: 
  MyClass(int index) { myArrayKeyValue = index; } 
  ~MyClass();
private:
int myArrayKeyValue;
}; 

int main() 
{ 
  MyClass testing[5] = { MyClass(1), MyClass (2), 
                   MyClass (3), MyClass (4), MyClass (5) };

  return 0; 
}
Dave18
Possible, but clearly not condensed :/ Are you up to writing (or copy/pasting) as many explicit constructions as there are instances ?
Mister Mystère
It depends if someone wants to initialize an array of objects with different value rather than using the loop sequence.
Dave18
A: 

It might be valuable to consider what end result you want and to try to achieve it by other means.

One way to proceed might be this:

std::vector<MyClass> v;
for (size_t i=0; i<nCount; i++)
    v.push_back(MyClass(static_cast<int>(i)));
Michael J
That would be the loop solution (for me the best, but he seems to want a construction method), but in this case myArrayKeyValue should be directly size_t, to avoid static_cast for example of a value greater than 2^15 (size_t is equivalent to unsigned int).
Mister Mystère