www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with insertBack

reply John Nixon <john.h.nixon1 gmail.com> writes:
I recently came across another problem with my program in D, 
found a minimal program showing it, and experimented a little 
with it as follows:

import std.stdio;
import std.container;
struct CS{
   char[] t;
   CS dup()const{
     CS cs;
     cs.t = this.t.dup;
     return cs;}
};
void main(){
   Array!CS cs_array = make!(Array!CS)();
   CS cs;
   cs.t = "bb".dup;
   cs_array.insertBack(cs);
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   cs.t[0] = ("a".dup)[0];//this changes cs_array!
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   cs.t = "c".dup;//but this does not
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   return;}

The first assignment to cs.t[0] changes cs_array as indicated, 
but the second to cs.t does not. Also if these two assignments 
are reversed, neither affects cs_array. What could be the 
explanation of this?

Kind regards

John Nixon
Jun 03 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/3/16 10:34 AM, John Nixon wrote:
 I recently came across another problem with my program in D, found a
 minimal program showing it, and experimented a little with it as follows:

 import std.stdio;
 import std.container;
 struct CS{
   char[] t;
   CS dup()const{
     CS cs;
     cs.t = this.t.dup;
     return cs;}
 };
 void main(){
   Array!CS cs_array = make!(Array!CS)();
   CS cs;
   cs.t = "bb".dup;
   cs_array.insertBack(cs);
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   cs.t[0] = ("a".dup)[0];//this changes cs_array!
You have inside your CS struct a pointer to a heap array. Then you change the heap array later. The CS element you put into the cs_array still points at the same piece of memory. Perhaps you meant to insert cs.dup?
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   cs.t = "c".dup;//but this does not
Right, because the cs stored on the stack is now pointing at a different heap-allocated array
   write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
   return;}

 The first assignment to cs.t[0] changes cs_array as indicated, but the
 second to cs.t does not. Also if these two assignments are reversed,
 neither affects cs_array. What could be the explanation of this?
Right, because if the stack is pointing at a different array than the cs_array[0], then altering won't affect cs_array[0]. -Steve
Jun 03 2016
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
On 06/03/2016 04:34 PM, John Nixon wrote:
 import std.stdio;
 import std.container;
 struct CS{
    char[] t;
    CS dup()const{
      CS cs;
      cs.t = this.t.dup;
      return cs;}
 };
Aside: No semicolon after struct declarations in D.
 void main(){
    Array!CS cs_array = make!(Array!CS)();
cs_array stores its data somewhere on the heap.
    CS cs;
cs is on the stack.
    cs.t = "bb".dup;
But cs.t's data is on the heap, like cs_array's. cs.t contains a pointer to it.
    cs_array.insertBack(cs);
This copies cs to cs_array's heap. The pointer in cs.t is being copied, but the data that it points to is not being copied. So cs.t and cs_array[0].t contain two distinct but equal pointers now. Since they're equal, they refer to the same data.
    write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
    cs.t[0] = ("a".dup)[0];//this changes cs_array!
This is expected since cs.t and cs_array[0].t point to the same location. A change to the data through one of them is visible to the other.
    write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
    cs.t = "c".dup;//but this does not
Here you're not writing through the pointer in cs.t, but rather you're assigning a whole new one. Since the pointers in cs.t and cs_array[0].t are independent of each other, they now point to different locations, with different data.
    write("cs_array = ");foreach(i2;cs_array)write(i2);writeln("");
    return;}
Jun 03 2016
parent John Nixon <john.h.nixon1 gmail.com> writes:
On Friday, 3 June 2016 at 15:03:45 UTC, ag0aep6g wrote:
 On 06/03/2016 04:34 PM, John Nixon wrote:
 import std.stdio;
 import std.container;
 struct CS{
    char[] t;
    CS dup()const{
      CS cs;
      cs.t = this.t.dup;
      return cs;}
 };
Aside: No semicolon after struct declarations in D.
 void main(){
    Array!CS cs_array = make!(Array!CS)();
cs_array stores its data somewhere on the heap.
    CS cs;
cs is on the stack.
    cs.t = "bb".dup;
But cs.t's data is on the heap, like cs_array's. cs.t contains a pointer to it.
    cs_array.insertBack(cs);
This copies cs to cs_array's heap. The pointer in cs.t is being copied, but the data that it points to is not being copied. So cs.t and cs_array[0].t contain two distinct but equal pointers now. Since they're equal, they refer to the same data.
    write("cs_array = 
 ");foreach(i2;cs_array)write(i2);writeln("");
    cs.t[0] = ("a".dup)[0];//this changes cs_array!
This is expected since cs.t and cs_array[0].t point to the same location. A change to the data through one of them is visible to the other.
    write("cs_array = 
 ");foreach(i2;cs_array)write(i2);writeln("");
    cs.t = "c".dup;//but this does not
Here you're not writing through the pointer in cs.t, but rather you're assigning a whole new one. Since the pointers in cs.t and cs_array[0].t are independent of each other, they now point to different locations, with different data.
    write("cs_array = 
 ");foreach(i2;cs_array)write(i2);writeln("");
    return;}
On Friday, 3 June 2016 at 15:03:45 UTC, ag0aep6g wrote: Thanks very much to you and Steve for the detailed explanation. By the way I did try insertBack(cs.dup) but wasn't sure what I was doing. It seems that I just need to add all the .dup 's when needed to make my program work and find out a procedure to make sure I don't miss any. John Nixon
Jun 03 2016