如何在C++或 Java 中"copied"数组

How is array being "copied" in C++ or Java

本文关键字:copied 数组 Java C++      更新时间:2023-10-16

基本上,问题是编译器如何管理内存。

 double[] b = {1.0, 2.0, 3.0};
 double[] a = new double[3]; //for Java
 double a[3]; //for C++
 a = b;

当声明数组a时,24字节的内存空间被分配给数组a

a=b简单地将数组b的引用的值复制到a

24字节的内存块呢?它将立即释放,还是在函数/方法结束时回收?

当数组a被声明时,24字节的内存空间被分配给数组a。

在C++中。在Java中,只有一个引用在声明中分配,数组本身在初始化器中分配。

a=b简单地将数组b的参考值复制到a。

在Java中。在C++中,它不是合法代码。

24字节的内存块呢?它将立即释放,还是在函数/方法结束时回收?

在C++中,它随着封闭作用域或更可能的封闭方法而消失。在Java中,当对它的最后一次引用消失时,它就有资格进行垃圾收集,在本例中,这就是方法的结束。

你的问题真的太复杂了,没有什么意义。试着一次用一种语言思考。

Java在变量超出范围时运行垃圾收集器。在这种情况下,如果函数中的最后一个方法是a = b,并且代码中没有其他对ab的引用,Java将取消分配用于数组的内存。

在C++中,在执行时,以下代码片段将提供错误作为无效的数组赋值

  a = b;

使用的代码段:

double b[] = {1.0, 2.0, 3.0};
double a[3]; //for C++
a = b; // error: invalid array assignment

相反,你必须做:

 memcpy(a, b, sizeof(a));

在C++中,数组有一个固定的起始(基)地址,不能重新分配。在Java中,数组类似于C++中的指针(在Java中称为引用),因此可以进行赋值。

在C++中,您的代码将无法工作;要么你必须有这样的东西:

#include <iostream>
#include <algorithm>
int main() {
    int b[] = { 4, 5, 6 };
    int a[3];
    std::copy_n(std::begin(b), std::end(a)-std::begin(a), std::begin(a));
    // the above is safer than just
    // std::copy(std::begin(b), std::end(b), std::begin(a))
    // in the case that the size of b is greater than the size of a...
    a[2] = 9;
    std::cout << b[2] << ' ' << a[2] << 'n';
}

(在这种情况下,ab的存储器都在堆栈上)或其较新的C++11等价物:

#include <iostream>
#include <memory>
int main() {
    std::array<int, 3> b { 4, 5, 6 };
    auto a = b; // or std::array<int, 3> a = b;
    a[2] = 9;
    std::cout << b[2] << ' ' << a[2] << 'n';
}

或者,如果您想要像java那样的可调整大小的数组,则必须使用vector:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> b { 4, 5, 6 };
    auto a = b;
    a[2] = 9;
    std::cout << b[2] << ' ' << a[2] << 'n';
}

在所有情况下,正如您在运行示例时所看到的,数组都是逐项复制的(所有三个示例都打印6 9),因此每个数组的存储将占用三个int变量(或24字节,在64位机器中)的空间——加上最后一种情况下vector的开销。。。

回答您的问题:在前两种情况下,当24个字节在堆栈上分配时,它会在返回时自动释放。在最后一种情况下,std::vector的析构函数也负责释放堆上的内存。

EDIT:我忘了举一个例子,在Java中,a只是对与b:相同的底层存储的引用的副本

#include <iostream>
#include <memory>
int main() {
    std::array<int, 3> b { 4, 5, 6 };
    auto& a = b; // or std::array<int, 3>& a = b;
    a[2] = 9;
    std::cout << b[2] << ' ' << a[2] << 'n';
}

(这也适用于vector,运行时会打印9 9

现在我明白了。

在Java 中

double[] b = {1.0, 2.0, 3.0};
double[] a = new double[3];
a = b;

a的声明不会导致24字节的内存块分配。仅创建一个引用变量。

在C++中,代码应该是

void myArray(double a[], int size_a){
    double c = 4.0;
    a = &c;
    cout << *a;
}
int main(){
    double b[] = {1.0, 2.0, 3.0};
    myArray(b, 3);
    return 0;
}

在这种情况下,a是一个指针。不是将整个数组传递给函数,而是仅将数组的起始地址复制到a

简而言之,在这两种语言中,只有一个数组在内存中创建。经过上述操作后,程序不会变得繁琐。