July 19, 2012
I have a 2 questions.

I have this code:

[code]
import std.stdio;

struct Test {
public:
	this(int i = 0) {
		writeln("Test CTor.");
	}

	this(this) {
		writeln("Test Copy CTor");
	}

	~this() {
		writeln("Test DTor");
	}
}

Test[] _arr;

void copy_save(Test t) {
	_arr ~= t;
}

void by_ref_save(ref Test t) {
	_arr ~= t;
}

[/code]

Why get i with

[code]
void main() {
	Test t = 42;

	by_ref_save(t);
}
[/code]

this output:

Test CTor.
Test Copy CTor
Test DTor

?

Why t is copied?

And the same if i have this:

[code]
void main() {
	Test t = 42;

	copy_save(t);
}
[/code]

t is already a clone. Why it is copied again?

Thanks in advance. :)
July 19, 2012
On 07/19/2012 02:27 PM, Namespace wrote:
> I have a 2 questions.
> 
> I have this code:
> 
> [code]
> import std.stdio;
> 
> struct Test {
> public:
>     this(int i = 0) {
>         writeln("Test CTor.");
>     }
> 
>     this(this) {
>         writeln("Test Copy CTor");
>     }
> 
>     ~this() {
>         writeln("Test DTor");
>     }
> }
> 
> Test[] _arr;
> 
> void copy_save(Test t) {
>     _arr ~= t;
> }
> 
> void by_ref_save(ref Test t) {
>     _arr ~= t;
> }
> 
> [/code]
> 
> Why get i with
> 
> [code]
> void main() {
>     Test t = 42;
> 
>     by_ref_save(t);
> }
> [/code]
> 
> this output:
> 
> Test CTor.
> Test Copy CTor
> Test DTor

As you mentioned in the subject the copy constructor is not called while
the struct is passed by reference but on array concatenation.
But this must occur since the array has its memory region and the
original variable t in main() also has. Since they are different, at
some point the struct must be copied from t in main() into the array.
The "ref" only ensures that it is passed via reference (a pointer to the
memory of t in main()) to the function by_ref_save().

> And the same if i have this:
> 
> [code]
> void main() {
>     Test t = 42;
> 
>     copy_save(t);
> }
> [/code]
> 
> t is already a clone. Why it is copied again?

Here it is once copied from t in main() into the local variable t in
copy_save() and then copied (as in your 1st example) into the array.
Imagine the copy_save routine is in a different module and only its
signature is exposed to main. When calling the function, the compiler
does not know what happens inside copy_save but it must put the variable
onto the stack at the position of the first parameter (well, in this
case it is probably put into a CPU register, but that doesn't matter here).

Then, when copy_save is invoked it only knows the local variable which it then copies into the array memory (after enlarging the array).

It *may* be the when you enable compiler optimizations (-O -inline) that copy_save gets inlined and hence the compiler can optimize one of the copy calls away. But that I don't know for sure.

Best regards,

Matthias
July 19, 2012
Is there any way to avoid the implizit copy ctor by array concatenation?
Or is the only way to use a pointer?
July 19, 2012
On 07/19/2012 03:00 PM, Namespace wrote:
> Is there any way to avoid the implizit copy ctor by array concatenation? Or is the only way to use a pointer?

Yes, in some way you have to. If you want to not copy a lot of data (or avoid additional on-copy effort) you either have to you pointers explicitly (Test*[]) or implicitly. The latter works e.g. by making Test a class which means that the variable actually does store a pointer to the instance.

Note that for struct pointers you should not escape them, i.e. have a variable local in a function, puts its address into some array and returning that array. Since the local variable is gone, the pointer is invalid as well. (Nothing happens if you do not access it).

Best regards,

Matthias
July 19, 2012
Ok, so if a put a struct into an array, it will copied into the array. But then? How it is deleted?

For exmaple, i have this code:

[code]
import std.stdio;

struct Test {
public:
	static uint _counter;

	this(int i = 0) {
		writeln("Test CTor.");

		_counter++;
	}

	this(this) {
		writeln("Test Copy CTor");

		_counter++;
	}

	~this() {
		writeln("Test DTor");

		if (_counter > 0) {
			_counter--;
		}
	}
}

void main() {
	{
		Test[] _arr;

		void copy_save(Test t) {
			_arr ~= t;
		}

		void by_ref_save(ref Test t) {
			_arr ~= t;
		}

		Test t = 42;

		//copy_save(t);
		by_ref_save(t);

		writeln("end scope");
	}

	writefln("Counter: %d", Test._counter);
}
[/code]

_counter is still 1 but the scope is released. How is that possible?
Even with _arr.clear(); at the end of the scope, _counter is still 1.
I see one CTor and one Copy CTor but only one DTor.

July 19, 2012
Use std.algorithm.move if you want to avoid the copy ctor call.
July 19, 2012
On Thursday, 19 July 2012 at 14:31:02 UTC, Timon Gehr wrote:
> Use std.algorithm.move if you want to avoid the copy ctor call.

With "move" I see the lost DTor call, but not without. Ist that a bug? o.O
July 19, 2012
On Thursday, 19 July 2012 at 15:36:01 UTC, Namespace wrote:
> _counter is still 1 but the scope is released. How is that possible?
> Even with _arr.clear(); at the end of the scope, _counter is still 1.
> I see one CTor and one Copy CTor but only one DTor.

_arr is actually a dynamic array, which allocates from the garbage collector. When _arr goes out of scope, you are only destroying the "Slice" that is looking at the data, but not the data itself. You have to wait until the Garbage Collector runs and collects.

Either that, or use a stack allocated static array, but I wouldn't recommend it.

Furthermore, D does not actually guarantee that all your objects are destroyed (eg. destructors called) when the program ends. D's approach is "The program has ended, ergo anything left in memory is moot. Just let the OS clear it."

If you really need RAII, you can use RefCounted objects, such as RefCounted! directly, or by using Array.
July 20, 2012
New question:

I have this code:
[code]
import std.stdio;

struct Test {
public:
	this(int i = 0) {
		writeln("CTOR");
	}

	this(this) {
		writeln("COPY CTOR");
	}

	~this() {
		writeln("DTOR");
	}
}

void main() {
	Test[] _arr;

	_arr ~= Test(0);

	writeln("end main");
}
[/code]

And as output i see:

CTOR
COPY CTOR
DTOR
end main

Why on earth....?

I create a struct Test. It's not a local variable, it's directly assigned,
but it is copied and the original is destroyed. Why?
If i store something important, like a pointer, in Test and will free him in the DTOR i cannot assign this way Test's to an array, because the pointer was deleted because the DTOr was called.

I think the correct output would be:

CTOR
end main

Maybe DTOR before "end main". But not COPY CTOR anywhere.
July 20, 2012
On Fri, 20 Jul 2012 14:50:19 +0100, Namespace <rswhite4@googlemail.com> wrote:

> New question:
>
> I have this code:
> [code]
> import std.stdio;
>
> struct Test {
> public:
> 	this(int i = 0) {
> 		writeln("CTOR");
> 	}
>
> 	this(this) {
> 		writeln("COPY CTOR");
> 	}
>
> 	~this() {
> 		writeln("DTOR");
> 	}
> }
>
> void main() {
> 	Test[] _arr;
>
> 	_arr ~= Test(0);
>
> 	writeln("end main");
> }
> [/code]
>
> And as output i see:
>
> CTOR
> COPY CTOR
> DTOR
> end main
>
> Why on earth....?
>
> I create a struct Test. It's not a local variable, it's directly assigned,
> but it is copied and the original is destroyed. Why?

Because that's how assignment works, rhs is evaluated, struct is constructed, then assigned to lhs, lhs copies the variable into the array.  Your variable is a struct, so it is copied.  Use a pointer instead and the pointer is copied into the array.  Use a reference and the reference is copied into the array.  The variable, whatever it is, is /always/ copied into the array.

It's a long standing optimisation issue and the reason for the recent distinction between lvalues and rvalues made in C++0x for their new 'move' optimisation where assignments involving rvalues/temporaries can move the rvalue instead of copying - or something like that, I'm a bit vague having watched a vid a few days back and not paying a lot of attention to it, sorry.

Does:

_arr[0] = Test(0);

avoid the copy construction?

R
« First   ‹ Prev
1 2 3 4 5 6
Top | Discussion index | About this forum | D home