tags:

views:

136

answers:

6

Hello

I have a such syntax in program

/* The Object1 is allowed to be changed */
class Object1 : BaseClass {
    BaseClass *link;
    int i;
    public: 
    Object1(int a){i=a;}
    Object1(int a, Object1 /*place1*/ o) {i=a; link= &o;}
};

int main(){
/* The initialization syntax must be preserved. No any new(), no other local objects b,c */
    Object1 a(1, /*place2*/ Object1(2));
    ...
}

What do I need in place1? I want to save a link (pointer) to the second object in the first object. Should I use in place1 reference "&"?

What type will have "Object1(2)" in place2? Is it a constructor of the anonymous object? Will it have a "auto" storage type?

Thanks

UPDATE:

In the place2, the syntax is fixed and I really must support creating of "chain", like

    Object1 a(1, Object1(2, Object1(6, Object1(999753))));

I can't add any symbol in the definiton of a.

UPDATE2: for place1: Object1(int a, Object1 &o) {i=a; link= &o;} and Object1 a(1, Object1(2)); in place2 I have a compile error (g++):

main.cpp||In function `int main()':|
main.cpp|19|error: no matching function for call to `Object1::Object1(int, Object1)'|
main.cpp|9|note: candidates are: Object1::Object1(const Object1&)|
main.cpp|14|note:                 Object1::Object1(int, Object1&)|
main.cpp|13|note:                 Object1::Object1(int)|
A: 

You can't use an instance of Object1 within the declaration of it (it's not declared yet). You can add something called a forward declaration ahead of the class declaration, like this:

// Forward declaration
class Object1;

// Now the class body
class Object1 {
    // some reference to Object1 here
};

However, I'm still not entirely clear what you're trying to do with this code. It might help to have a little more information about what you want this constructor to do? I suspect you might want to be using a pointer or a pass-by-reference, and not a pass-by-value.

Mike Mueller
I want to construct tree(in real code) or list(in this example code) in form of (this form is fixed and I cant use any other form. I should write a class, which can be initialized with such code)`Object1 an_object (1,Object1(2,Object1(3,Object1(10,Object1(0)))))`. But I don't understand, what will be a 'anonymous constructors' here? What is the type and meaning of "Object1(0)" in the such declaration. Thanks.
osgx
A: 

The constructor argument o is a copy of the Object1 instance you passed in (since it's being passed by value. In your constructor, when you set your member pointer to its address, that address is the stack frame, which will be invalid after your constructor returns.

Here's another way to do this (there are other ways, of course):

class Object1 : BaseClass
{
    BaseClass *link;
    int i;

public: 
    // - Prefer initialization to assignment
    // - Initialize ALL of your members
    Object1(int a) : link(NULL), i(a) {}

    // This instance assumes ownership of p
    Object1(int a, Object1 *p) : link(p), i(a) {}

    ~Object1() { delete link; }
};

int main()
{
    Object1 a(1, new Object1(2));
    ...
}

EDIT: Hmmmm, the only way I can see for you to use the chaining design you have is something ugly like this:

class Object1 : BaseClass
{
    BaseClass *link;
    int i;

public:
    Object1(int a) : link(NULL), i(a) {}

    Object1(int a, const Object1& o) : link(new Object1(o)), i(a) {}

    // Copy constructor
    Object1(const Object1& other) : link(NULL), i(other.a)
    {
        // Deep copy linked object
        if (other.link != NULL)
        {
            link = new Object1(*other.link);
        }
    }

    // Assignment operator that does deep copy
    const Object1& operator=(const Object1& that)
    {
        // Check for assignment to self
        if (this != &that)
        {
            delete this.link; 
            this.link = NULL;

            // Deep copy linked object
            if (that.link != NULL)
            {
                this.link = new Object1(*that.link);
            }

            this.i = that.i;
        }
    }

    ~Object1() { delete link; }
};

int main()
{
    Object1 a(1, new Object1(2));
    ...
}
Scott Smith
sorry, this will work, but I must support original syntax `Object1 a(1, Object1(2));`
osgx
+2  A: 

Place 1: Use a pointer (*) instead of a reference (&) here. Pointer syntax more explicitly indicates a link.

Place 2: What's known as a 'temporary' object will be created here. Yes, it will involve a call to the constructor of Object1. Also, yes, the storage will be 'auto' as it will be created on the stack.

Be careful, however. The temporary will die before you can refer to it inside the constructor. This would surely crash your program.

If you must pass a temporary, you may succeed by creating a copy it on the heap. Something like this:

class Object1
{
    BaseClass* link;
    int i;
    Object1(int a) : i(a), link(NULL) {}
    Object1(int a, const Object1& o) : i(a), link(new new Object1(o)) {} 
    Object1(const Object1& other) i(other.i) link(other.link) {} //Copy constructor
    virtual ~Object1() { delete link; } //Don't forget the 'delete' in destructor.
};

Then in your main you can() do this:

int main() 
{
    Object1 a(3, Object1(2));
    ....
}

Do notice the destructor in Object1 class. Make sure to call delete operator on your link inside it. Such a call would cause deletion of all children down the chain, however. If this is not what you want, alter your deletion mechanism accordingly. In any case, don't forget to delete.

Also, make sure the destructor is virtual. That's because you'll be calling delete on the base class pointer that points to a derived class object.

Frederick
Will this temporary object be returned (from constructor) by value, by reference or by pointer?
osgx
Constructors don't return anything like other functions. However, to answer your actual question, as a result of the constructor call you will end with the actual object, not a reference or a pointer. So you'll have to use the address operator to obtain its address. However, as others have warned, this 'temporary' will pretty much immediately die after it's created. So you're bound to end up with a bad pointer. You should instead create a local variable and pass the address of that variable here.
Frederick
Yes, with more local variables my code works ok. But I must to support such chaining syntax.
osgx
This temporary constructor is just an expression. Any expression have a type of entire expression. So I call this 'constructor call which will return smth'
osgx
Then create your objects on heap, using the 'new' operator. Something like this perhaps: Object1 a = new Object1(1, new Object1(2));Heap based objects won't die automatically, unlike that temporary.
Frederick
I can't change syntax of place2. The task is to support such syntax
osgx
By the way, if you must chain, and still want to support the syntax without the new operator (Object1 a(... Object1(2))) etc, then you should do this: inside Object1's constructor copy the temporary passed into another object created on heap. The temporary will still die, but you'll have a valid copy of it with you.
Frederick
Yes, it will be a solution of my problems. But, take a look on update2: I can't add anything in place1.
osgx
+4  A: 

In "place1", you need a reference. Object1 isn't fully defined, so you can't take it by value. That said, you wouldn't want to pass by value; when you take the address of it, you'd be getting the address of the copy, not the actual object.

Since you only want a pointer to a BaseClass, it might make more sense to only place that restriction on the parameter. (Of course, if you really need an Object1, reflect that in the type of link: Object1* link;).

Also consider using an initialization list:

Object1(int a) : i(a), link(0) /* <- important! */ { }
Object1(int a, BaseClass& o) : i(a), link(&o) { }

Always use an initialize list.

"place2" creates an unnamed instance of Object1 using a constructor. It has no storage(?) auto storage, and dies at the end of the expression.

That is, once you've hit the semicolon in Object1 a(1, /*place2*/ Object1(2));, it ceases to exist and you have a pointer to an non-existent object! This results in undefined behavior.

Give it a lifetime beyond the expression:

Object1 x(2);    
Object1 a(1, x);

Always make sure that when you refer an object, it will live the entire time you refer to it.


Your new compile error is because you can't have a reference to a temporary variable. You can have one with a const-reference, though. The thing is, your pointer needs to point to a const BaseClass now, which may dampen what you want.

Again, your design needs reworking, unfortunately.

GMan
I can change code before place1 to BaseClass. Will it help me?
osgx
@osgx: That would work too, and is probably preferred. since you only need a pointer to a `BaseClass`, may as well take a reference to one. (Not by value! You'll slice it. http://en.wikipedia.org/wiki/Object_slicing)
GMan
You can't pass it by value no matter what type you decide to use, because then you'll store the address of the copy, which is certainly not what is desired.
Dennis Zickefoose
@Dennis: Of course, thanks. Missed that completely. @Everyone: Does a temporary have `auto` storage or no storage? EDIT: Seems to be `auto`, all objects have storage.
GMan
@GMan, I have a compile error with reference char used in the first place. See update2
osgx
A: 

What you want to do isn't possible, as you've written it. The lifetime of the Object1 at /*place2*/ ends after the constructor does, so you'll have a dangling pointer.

In general, you'll want the Object1 at /*place2*/ to be a reference, or a pointer directly [in which case you wouldn't take the address, just copy it directly].

But, you'll have to be pretty careful of the lifetime of the pointer you store, as is evidenced by the initial point.

Dennis Zickefoose
A: 

What you are trying to implement is a dynamic array on the stack. You want to create a list of objects and keep none of them in the heap. C++ doesn't support that, at least not in the scope of one function.

You could refactor your code with recursion and keep a linked list going up the stack, but that wouldn't be very C++ -ish.

Otherwise, the only solution is to use the heap (std::list, std::auto_ptr or std::unique_ptr should do the trick), as others have suggested.

Potatoswatter
I need to support the syntax given in place2. Actyually, in my task there is no list, but a tree. The list is only small example. I had very specific question and need no deep refactoring. Thanks
osgx