digitalmars.D.learn - Unexpected behavior when using both alias this and object pointer
- xiren7 (41/41) Jan 12 2017 The problem and the code:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (48/48) Jan 12 2017 Hiding a Foo right after Impl can be a solution. However, you need to
- xiren7 (59/59) Jan 12 2017 Thanks. Ali.
The problem and the code:
import std.stdio: writeln;
import core.stdc.stdlib: malloc;
struct Impl {
ubyte[8] payload;
}
class Foo {
Impl *impl;
alias impl this;
this()
{
impl = cast(Impl*) malloc(Impl.sizeof);
}
}
class Foo2 {
ubyte[8] payload;
}
void main()
{
// alias T = Foo2;
alias T = Foo;
auto t = new T();
// what I want to do is:
// 1. cast t as pointer
// 2. passe the pointer to a extern(C) callback function
// 3. cast the pointer back to t in extern(C) callback
function
// 4. accesse the payload field
auto payload = (cast(T) cast(void*) t).payload; // -> crashs
// the right way to get the address of the t object
writeln(*cast(void**) &t); // -> 278E3373000
// the unexpected behavior
// the obvious(but wrong) way to get the address of the t
object
writeln(cast(void*) t); // -> 278E164DAB0
// because of alias this
// cast(void*) t == cast(void*) t.payload
writeln(cast(void*) t.payload); // -> 278E164DAB0
}
My question is should let the compiler generate a warning about
this unexpected(maybe) behavior?
Jan 12 2017
Hiding a Foo right after Impl can be a solution. However, you need to
pass 't', not '&t' to the C function because
- Although it may be unexpected, cast(void*) is the specified way of
getting the address of a class object
- Taking the address of a class reference (which 't' is one), is just
the address of the reference itself
So, you either have to do something similar to the following or pass
void* to the C function.
import std.stdio: writeln;
import core.stdc.stdlib: malloc;
struct Impl {
ubyte[8] payload;
}
struct ImplWithOwner {
Impl impl;
Foo owner;
}
class Foo {
ImplWithOwner *io;
Impl *payload() {
// Guaranteed by D for structs:
assert(cast(void*)io == cast(void*)&io.impl);
return &io.impl;
}
alias payload this;
this() {
io = cast(ImplWithOwner*) malloc(Impl.sizeof);
io.owner = this;
}
}
static Foo asFoo(Impl* p) {
return (cast(ImplWithOwner*)p).owner;
}
extern(C)
void actual_C_function(Impl* data, void function(Impl*) callback) {
data.payload[0] = 42;
callback(data);
}
extern(C)
void myCallback(Impl* p) {
auto foo = p.asFoo;
assert(foo.io.impl.payload[0] == 42);
}
void main() {
auto t = new Foo();
actual_C_function(t, &myCallback);
}
Ali
Jan 12 2017
Thanks. Ali.
My previous post is not clear that I have to store class
reference(object pointer) in void*.
My actual code is try to use libuv in D.
// genarated from uv.h, only two fields is used: 'data', 'type'.
// the document of 'data': "Space for user-defined arbitrary
data. libuv does not use this field".
// uv_timer_t is the subclass of uv_handle_t in C. (uv_timer_t
has all the fields defined in uv_handle_t)
struct uv_handle_t {align(8):
union {
struct {void* data; void* _; uv_handle_type type;}
ubyte[96] _payload;
}
}
struct uv_timer_t {align(8):
union {
struct {void* data; void* _; uv_handle_type type;}
ubyte[160] _payload;
}
}
...
// try to resemble the libuv object defined in C.
struct UVHandle {
uv_handle_t _uvHandle;
// subclass uv_handle_t
alias _uvHandle this;
void close() { // uv_close(&this) }
bool isClosing() { // uv_is_closing(&this) }
...
}
// define Timer as 'final class', in order to force Timer
allocated in gc.
final class Timer {
UVHandle* uvHandle
// subclass UVHandle
alias uvHandle this;
...
this()
{
// malloc memory(nogc) for uv_timer_t.
uvHandle = malloc(uv_timer_t.sizeof)
// store the timer object reference in 'data',
// but 'alias uvHandle this' also overrides 'cast',
// this is the problem described as my previous post.
uvHandle.data = cast(void*) this;
}
~this() { free(uvHandle); }
void start(...) { // uv_timer_start(this.uvHandle, ...) }
void stop() { // uv_timer_stop(this.uvHandle) }
...
}
My current solution is using 'mixin template' instead of 'alias
this' as the way to subclass:
mixin template UVHandle() { ... }
public final class Timer {
mixin UVHandle;
...
}
Jan 12 2017








xiren7 <nirvana117 gmail.com>