链接时如何了解对象是否被复制或引用

时间:2018-09-04 02:21:43

标签: c#

对不起,我是编程新手,所以我的描述可能不正确。我设计了一个使用linkedNode结构的类:

#include <iostream>
#include <ctime>
#include <ratio>
#include <chrono>
#include <array>
#include <omp.h>

int main() {

  using namespace std::chrono;

  const int big_number = 1000000000;
  alignas(64) std::array<double, 6*8> array = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

  // Sequential

  high_resolution_clock::time_point start_linear = high_resolution_clock::now();

  for(int i = 0; i < 6; i++) {
    for(int j = 0; j < big_number; j++) {
      array[i]++;
    }
  }

  high_resolution_clock::time_point end_linear = high_resolution_clock::now();

  // Parallel

  high_resolution_clock::time_point start_parallel = high_resolution_clock::now();

  array = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

      #pragma omp parallel
  {
            #pragma omp for
    for(int i = 0; i < 6; i++) {
      for(int j = 0; j < big_number; j++) {
        array[i*8]++;
      }
    }
  }

  high_resolution_clock::time_point end_parallel = high_resolution_clock::now();

  // Stats.

  std::cout << omp_get_num_procs() << " processors used." << std::endl << std::endl;

  duration<double> time_span = duration_cast<duration<double>>(end_linear - start_linear);
  std::cout << "Linear action took: " << time_span.count() << " seconds." << std::endl << std::endl;

  time_span = duration_cast<duration<double>>(end_parallel - start_parallel);
  std::cout << "Parallel action took: " << time_span.count() << " seconds." << std::endl << std::endl;

  return EXIT_SUCCESS;
}

和主要:

--no-ff

因此可以无限期地调用我的next(),但是我很好奇class test { public int data, public test next; public test(int data){this.data = data;} } 如何与public static void main(){ test t1 = new test(1), t2 = new test(2); //Line 1 t1.next = t2; //Line 2 t2.next = t1; //Line 3 t2 = null; //Line 4 Console.Write(t1.next.next.next.......data) // Line 5 } 连接?如果将t2复制到t1.next,则第3行将无法使其成为循环;如果t2仅按地址链接,则第4行将中断循环。所以我很困惑代码后面会发生什么?

2 个答案:

答案 0 :(得分:4)

实际上,您的结论都不正确。不会创建该对象的副本,但是第4行不会“破坏循环”。让我们分解一下:

test t1 = new test(1), t2 = new test(2); //Line 1

这将创建两个“测试”对象,并将它们的引用存储在局部变量中。由于它们每个都有一个标识它们的值(在此示例中不变),我们将它们称为“事物1”和“事物2”

t1.next = t2; //Line 2

好。现在,“事物1”的next属性引用了“事物2”(从技术上讲,t2 value -对“事物2”的引用)被复制到{{ 1}})

t1.next

仍然很好。现在,“事物2”的t2.next = t1; //Line 3 属性引用了“事物1”(从技术上讲,next value -对“事物1”的引用)被复制到{{ 1}})

t1

好。 变量 t2.next现在什么也没有指向。此处的主要误解是 “事物2”没有任何变化 。仅WAS引用“事物2”的变量发生了变化。 “事物2”本身不受影响。它仍然具有引用“事物1”的t2 = null; //Line 4 属性。因此,“事物1”也不受影响。它具有一个引用“事物2”的t2属性

next

next引用“事物1”,其 Console.Write(t1.next.next.next.......data) // Line 5 属性引用“事物2”,其t1属性引用“事物1”,其next属性引用“事物” 2”等。因此,根据您呼叫next的次数,结果将为next.next

  

我很好奇t2如何连接到t1.next?

直到第4行,它们都引用同一对象。然后,第4行会更改1引用的内容(无),但不会更改2的值。

答案 1 :(得分:1)

D Stanley的回答非常好,但是我想用更细粒度的步骤进行更真实的类比,这可能会帮助您继续前进。我将遍历代码的每个部分,并将其转换为此类比。我在构造函数中更改了参数名称,以使事情更清晰一些。

class test {

您创建了一个称为“测试”的制造说明,该说明应将什么包装在纸板箱中以及如何将其放入其中。

    public int data,

将有一张纸条,纸条上将印有“数据”标签,该纸条上将有一个写在-2,147,483,648和2,147,483,647之间的数字点。纸张的默认值为0。

    public test next;

另一张标有“下一张”的纸将放入包装盒中,这是一张特殊的纸,仅允许您在用来存放“测试”盒的架子上的位置书写。默认情况下,此位置将留空。

    public test(int newData){this.data = newData;}     
}

这是包装说明,说明说“我会给您一张标有“ newData”的纸条,上面有一个数字。您应在包装箱中的“ data”纸条上书写。我给你的单据“ newData”中的数字。完成后,就扔掉我最初给你的标有“ newData”的纸条。”

public static void main() -->{<--

你去上班。

    test t1 = -->new test(1)<--

您去找供应商,订购一个“测试”盒,并给他们一张纸条,上面有1。他们把这箱子运到仓库。

    --> test t1 =<-- new test(1), t2 = new test(2); //Line 1

您被告知您的盒子坐在架子0xAAAAAAAA上,您打印出那只特殊纸,只允许在上面写上带有标签“ t1”的架子编号,并在上面写上值0xAAAAAAAA。 / p>

    test t1 = new test(1), -->t2 = new test(2);<-- //Line 1

您重复前面的两个步骤,但是这次给制造商一个2,标签为t2的纸条上写有0xBBBBBBBB。

    -->t1.<--next = t2; //Line 2

转到“居所”,然后在框上找到名称与标签为t1(架子0xAAAAAAAA)的纸张上写的数字相匹配的架子。

    t1-->.next = t2<--; //Line 2

打开该架子上的盒子,在纸条上写上“ next”,该数字是您在“ t2”纸上的编号(0xBBBBBBBB)。将“下一张”纸留在盒子中,然后用“ t2”纸回到办公室。

    -->t2.<--next = t1; //Line 3

转到院子里的盒子里,架子名称与写在t2纸上的数字相匹配(架子0xBBBBBBBB)。

    t2-->.next = t1<--; //Line 3

打开该架子上的盒子,在纸条上写上“ next”,该数字是您在“ t1”纸上的编号(0xAAAAAAAA)。将“下一张”纸留在盒子中,然后用“ t1”纸回到办公室。

    t2 = null; //Line 4

抹掉标记为“ t2”的纸上的数字

    Console.Write(-->t1.<--next.next.next.......data) // Line 5

转到院子里,找到上面有写在“ t1”(0xAAAAAAAA)上的数字的架子,然后找到上面的盒子。

    Console.Write(t1.-->next.<--next.next.......data) // Line 5

在您当前位于(0xAAAAAAAA)的框中,阅读标有“下一页”的纸,然后找到编号为(0xBBBBBBBB)的书架

    Console.Write(t1.next-->.next.<--next.......data) // Line 5

在您当前位于(0xBBBBBBBB)的框中,阅读标有“下一页”的纸,然后找到具有该数字(0xAAAAAAAA)的架子

    Console.Write(t1.next.next-->.next.<--......data) // Line 5

在您当前位于(0xAAAAAAAA)的框中,阅读标有“下一页”的纸,然后找到编号为(0xBBBBBBBB)的书架

    Console.Write(t1.next.next.next-->.......<--data) // Line 5

每次在读取0xAAAAAAAA和0xBBBBBBBB上的框之间来回跳动时,每次读取“ next”的值并转到纸张上写有该框的位置。

    Console.Write(t1.next.next.next......-->.data<--) // Line 5

在您当前位于(?)的框中,阅读标有“数据”的纸

    -->Console.Write(t1.next.next.next.......data)<-- // Line 5

将写在“数据”纸上的数字提供给“控制台”公司,并告诉他们您要他们“写”它。

}

你一天回家。

在盒子上写下原始值之后,您再也不会对其进行修改,只会删除您办公室里的那张纸的编号,因此擦除该编号不会影响阅读“下一张”在两个盒子里的纸。


以下是有关使用相同类比如何获取对象垃圾的一些小信息。

    t2 = null; //Line 4
    --><---
    Console.Write(t1.next.next.next.......data) // Line 5
}

您将带有“ t2”标签的纸丢掉,因为在接下来的工作日中不会使用“ t2”。

    t2 = null; //Line 4
    Console.Write(t1.next.next.next......-->.data<--) // Line 5
    --><---
}

您扔掉标有“ t1”的纸,因为在接下来的工作日中将不再使用它。

 public static void main() -->{
    test t1 = new test(1), t2 = new test(2); //Line 1
    t1.next = t2; //Line 2
    t2.next = t1; //Line 3
    t2 = null; //Line 4
    Console.Write(t1.next.next.next.......data) // Line 5
}<--

在一天中的某个时候,如果管理人员认为房屋太满了,他们会经过每个人的办公室,他们会发现所有纸条上都写有任何种类的仓库货架,并将这些货架标记为“已使用” ,然后他们转到那些用过的书架中的箱子,并在箱子内找到其他任何架子编号。他们重复此过程,直到所有可以标记为已使用的框都被标记为止。然后,他们扔掉了所有未标记的用于腾出空间的盒子。