www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Copy instead of reference?

reply "Namespace" <rswhite4 googlemail.com> writes:
I get this output:

====

----
CTor 42
DTor 0
Return A
Postblit 42
----
DTor 84
DTor 42

====

with the following code. I'm a bit confused about the Postblit. I 
return by ref so I thought that I get a const ref of the original 
A.

[code]
import std.stdio;

struct A {
public:
	int id;

	this(int id) {
		writeln("CTor ", id);

		this.id = id;
	}

	this(this) {
		writeln("Postblit ", this.id);

		this.id *= 2;
	}

	~this() {
		writeln("DTor ", this.id);
	}
}

class B {
private:
	A _a = void;

public:
	this() {
		this._a = A(42);
	}

	ref const(A) getA() const {
		writeln("Return A");
		return this._a;
	}
}

void main() {
	writeln("----");
	B b = new B();
	A a = b.getA();
	writeln("----");
}
[/code]
May 23 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
Forget to say: I use dmd 2.062.
May 23 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
I've filled a bug report.
May 23 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 05/23/13 11:47, Namespace wrote:
 I get this output:
 
 ====
 
 ----
 CTor 42
 DTor 0
 Return A
 Postblit 42
 ----
 DTor 84
 DTor 42
 
 ====
 
 with the following code. I'm a bit confused about the Postblit. I return by
ref so I thought that I get a const ref of the original A.
     ref const(A) getA() const {
         writeln("Return A");
         return this._a;
     }
     A a = b.getA();
You do, but you then assign to another 'A'... artur
May 23 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
That was what I also expected. But opAssign is not called.
May 23 2013
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 23 May 2013 13:29:49 +0200, Namespace <rswhite4 googlemail.com>  
wrote:

 That was what I also expected. But opAssign is not called.
Because you have a postblit. It's called instead of opAssign. -- Simen
May 23 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 23 May 2013 at 11:31:19 UTC, Simen Kjaeraas wrote:
 On Thu, 23 May 2013 13:29:49 +0200, Namespace 
 <rswhite4 googlemail.com> wrote:

 That was what I also expected. But opAssign is not called.
Because you have a postblit. It's called instead of opAssign.
[code] import std.stdio; import std.c.string : memcpy; struct A { public: int id; this(int id) { writeln("CTor ", id); this.id = id; } this(this) { writeln("Postblit ", this.id); this.id *= 2; } void opAssign(ref const A a) { writeln("opAssign L: ", a.id); this.id = a.id; } void opAssign(const A a) { writeln("opAssign R ", a.id); memcpy(&this, &a, A.sizeof); } ~this() { writeln("DTor ", this.id); } } class B { private: A _a; public: this() { this._a = A(42); } ref A getA() { writeln("Return A"); return this._a; } } void main() { B b = new B(); A a = b.getA(); } [/code] Output: ---- CTor 42 opAssign R 42 DTor 42 Return A Postblit 42 DTor 84 DTor 42 ---- Postblit, no opAssign call.
May 23 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
To be more detailed:

I'd expected that the code with 'getA' without ref

[code]
	A getA() {
		writeln("Return A");
		return this._a;
	}
[/code]

would print this output:

----
CTor 42
opAssign R 42
DTor 42
Return A
Postblit 42
opAssign R 84
DTor 84
DTor 42
----

And with 'getA' with ref

[code]
	ref A getA() {
		writeln("Return A");
		return this._a;
	}
[/code]

would print this output:

----
CTor 42
opAssign R 42
DTor 42
Return A
opAssign L 42
DTor 42
DTor 42
----
May 23 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 05/23/13 13:34, Namespace wrote:
     A a = b.getA();
 Postblit, no opAssign call.
 
You're constructing, not assigning. Try reassigning 'a' to see opAssign in action. It's a bit unintuitive and easy to miss - which I did too, hence my misleading first reply - sorry. The issue is that D has no ref vars, so you can't really keep the returned refs around, other than passing them to another func. artur
May 23 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
I know that D has (sadly) no C++ references, but I still think 
that

A a = some_existing_A;

should call opAssign.
May 23 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
And if I do this:

A a;
a = b.getA();

I get what I want. What a spasm...
May 23 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 23 May 2013 at 11:57:04 UTC, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think 
 that

 A a = some_existing_A;

 should call opAssign.
Now I see what has you confused. Whether postblit or opAssign is called, depend on left, not right side of assignment. Object 'a' didn't exists prior, so postblit is called, and copy ctor is called with respect of 'a' as 'this' argument.
May 23 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 23 May 2013 at 12:07:40 UTC, Maxim Fomin wrote:
 On Thursday, 23 May 2013 at 11:57:04 UTC, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think 
 that

 A a = some_existing_A;

 should call opAssign.
Now I see what has you confused. Whether postblit or opAssign is called, depend on left, not right side of assignment. Object 'a' didn't exists prior, so postblit is called, and copy ctor is called with respect of 'a' as 'this' argument.
What had confused me, was the point, that it doesn't matter if you return by value or by ref, you get the same output for this specific case. That did not feel right. But thanks to you.
May 23 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 23 May 2013 at 11:57:04 UTC, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think 
 that

 A a = some_existing_A;

 should call opAssign.
Actually, it is similar to C++ : http://codepad.org/lkPMU1Ne
May 23 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 05/23/13 13:57, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think that
 
 A a = some_existing_A;
 
 should call opAssign.
Not opAssign, but user-defined copy-constructor. But D does not have them either... artur
May 23 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 23 May 2013 at 12:29:04 UTC, Artur Skawina wrote:
 On 05/23/13 13:57, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think 
 that
 
 A a = some_existing_A;
 
 should call opAssign.
Not opAssign, but user-defined copy-constructor. But D does not have them either... artur
That would be a solution.
May 23 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 05/23/13 14:30, Namespace wrote:
 On Thursday, 23 May 2013 at 12:29:04 UTC, Artur Skawina wrote:
 On 05/23/13 13:57, Namespace wrote:
 I know that D has (sadly) no C++ references, but I still think that

 A a = some_existing_A;

 should call opAssign.
Not opAssign, but user-defined copy-constructor. But D does not have them either...
That would be a solution.
They are required anyway, for several reasons. Right now, you /can/ do: A a = A(some_existing_A); but, because 'A a = some_existing_A' will bypass your cpctor and call the postblit, it's too dangerous. Unless you mark the latter as disabled, which of course causes other problems. artur
May 23 2013