Thread overview
[Issue 1778] New: Can not create pointer to class reference
Jan 10, 2008
d-bugmail
Jan 16, 2008
d-bugmail
Jan 17, 2008
d-bugmail
Jan 17, 2008
d-bugmail
Jan 17, 2008
d-bugmail
Jan 17, 2008
d-bugmail
Jan 18, 2008
d-bugmail
Jan 18, 2008
d-bugmail
January 10, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778

           Summary: Can not create pointer to class reference
           Product: D
           Version: 1.026
          Platform: PC
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: aarti@interia.pl


Below doesn't compile:
----
A* cp = new A*;
----
Type of new A* is (A**) while it should be A*.

Reference: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=10683


-- 

January 16, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778


bugzilla@digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID




------- Comment #1 from bugzilla@digitalmars.com  2008-01-16 04:27 -------
In general,
   new T;
will return a value of type T*, unless T is a reference type (i.e. a class or
an array), in which case it returns a value of type T.
Therefore,
   new T*;
will allocate a pointer to T, and return a value which points to that pointer
to T. In other words, a T**.

This is as designed.


-- 

January 17, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778


aarti@interia.pl changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |




------- Comment #2 from aarti@interia.pl  2008-01-17 03:15 -------
Well, the problem is not that simple as it seems to be...

Currently it is NOT possible to create in sane way pointer to class reference
on heap. It affects also all types of form:
A**, A***, A**** ...., where A is a class
because to initialize them it is necessary at last to initialize A*.

Because of pointer is not created, there is no way to initialize such a variable.

More comments in below example:
import std.stdio;

T create(T)() {
    static if (is(T == class))
        return new T;
    else
        return *(new T);
}

class A { void test() {writefln("Ok!");}}
struct B {}

void main() {
    //Does not create pointer to A in memory
    A* x = *(new A*);
    writefln("x is null: ", x is null);
    //*x = new A; //access violation, because x is null as only
                  //first pointer is created

    //How to initialize below variable?
    A** y = new A*;
    //*y = ????


    //Workaroud 1
    A* u = cast(A*) new B;
    *u = new A;
    u.test;

    //Workaround 2
    static A ca;
    ca = new A;
    u = &ca;
    //unfortunately in this case there remains memory leak

    //Workaroud 3
    //IMHO best long term solution, but it is difficult for me to predict all
    //consequences
    //Allow that typeof(A*) == typeof(A)
    //and typeof(&A) == typeof(A)
    //for classes. It will allow also to create one create function for
    //all types:
    //T* create(T)() {
    //  return new T;
    //}

    //Workaround 4
    //When creating (new A*)
    //initialize not only first pointer
    //but also second, so that
    // *(new A*) is not null
}


-- 

January 17, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778


bugzilla@digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |INVALID




------- Comment #3 from bugzilla@digitalmars.com  2008-01-17 15:04 -------
C c = new C;
C* pc = new C*;
*pc = &c;

Note that it appears you are asking that:
   new C*;
allocate both a C and a pointer to C as two separate allocations. This is not
done for the same reason that:
   new int*;
does only one allocation - not two.


-- 

January 17, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778





------- Comment #4 from aarti@interia.pl  2008-01-17 16:16 -------
Well, your solution is IMHO wrong for most real-life use cases. (And that was my first try to solve problem).

BTW your example should look like below (there is an error in your's):
C c = new C;
C** ppc = new C*;
*ppc = &c;

And now, let's put this code into function which returns pointer to C:
---
import std.stdio;
class C {void test() {writefln("Ok");}}

C* func() {
    C c = new C;
    C** ppc = new C*;
    *ppc = &c;
    return *ppc;
}

void main() {func.test;}

---
Something that I don't understand in above code is the fact that it... works! But it should definitely not!

Please notice in function func that there is address of local variable taken. After exiting scope this address might be very quickly invalid. Without all this pointer machinery, when you put just return &c; at the end of function you get from compiler:

src/quicktest.d(7): Error: escaping reference to local variable c

IMHO it works just because of some specific stack access optimization in my/others? computer. Or compiler makes some magic?

I don't know why it works, but IMHO this bug should be reopened...


-- 

January 17, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778





------- Comment #5 from bugzilla@digitalmars.com  2008-01-17 16:45 -------
1) Why is it wrong for real live cases?
2) You're right, pc should be declared C**
3) The return "worked" because the value still existed, undamaged, on the
stack. The stack cleanup just adjusts the ESP, it doesn't actually stomp on the
values


-- 

January 18, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778





------- Comment #6 from bugzilla@digitalmars.com  2008-01-17 18:13 -------
You can also write:

class C { }
void test()
{
 C c = new C;
 C* pc = (new C[1]).ptr;
 *pc = c;
}


-- 

January 18, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=1778





------- Comment #7 from aarti@interia.pl  2008-01-18 02:50 -------
> 1) Why is it wrong for real live cases?

Because probably in most cases, when you will need something like pointer to
class you will need also to return it from function.
And then you have a problem with escaping reference to local variable.

> 3) The return "worked" because the value still existed, undamaged, on the stack. The stack cleanup just adjusts the ESP, it doesn't actually stomp on the values

Well it confirms that it was just plain luck, that program was working...

4) (answer to your next comment)
class C { }
void test()
{
 C c = new C;
 C* pc = (new C[1]).ptr;
 *pc = c;
}

It seems to be similar workaround like number 1 from my workaround list? And as I assume it should work when returning from function?

-------------

It's nice that there are workarounds which are actually working right now. But
IMHO they are still only workarounds (quick hacks). And according
to principle "No issue left behind", it should be rather solved than hacked.

Maybe you would consider my proposition:
*** For A being a class, types A and A* should be implicitly castable between
each other. ***

Known consequences (probably just iceberg top, but let me start):
1. In index of associative array: if type of index is A* array should be
indexed by pointer, if type of index is
A, array should be indexed by opHash
2. Proper reductions needs to be applied for types like A**, A*** etc. (see
below)
...

Advantages:
It will reduce number of necessary workarounds in code:

1. In constructor-like functions:
# T* create(T)() {
#   return new T;
# }

instead of currently necessary:
T create(T)() {
    static if (is(T == class))
        return new T;
    else
        return *(new T);
}

2. When storing pointers to class in associative arrays.
Currently I have to cast A to (void*) to store into associative array. With new
solution I would just declare array index as A* and put class there.

3. It solves cleanly problem of creation pointer to class

A** p = new A*;

which, after reduction is same as:
(A*)* p = new (A*); and
A* p = new A;


4. This change is not sophisticated workaround to hide real state of matter, but rather exposes real state of matter which is that new A; creates pointer to class A.

Anyway I would say that this bug should stay open, till sane solution will be found.


--