#include <iostream>
#include <string>
using namespace std;
static inline string BoolToString(bool boolean_exp) {
    return boolean_exp? "True" : "False";
}
class Foo {
public:
    explicit Foo(int _size) noexcept : 
        my_resource(new int[_size]) {
        cout << "Foo obj init, at: " << this << ", my_resource at:" << my_resource <<endl;
        my_resource[0] = 1234567;
    }
    ~Foo() {
        cout << "A Foo instance at: " << this << " is finalizing; ";
        cout << "my_resource: " << my_resource << endl;
        delete[] my_resource;
        my_resource = nullptr;
    }

public:
    int *my_resource = nullptr;
};

void function_foo(Foo f) {
    cout << "function_foo() invoked" << endl;
}

int main(int argc, char *argv[]) {
    Foo foo(20);
    function_foo(foo); // I think, foo's copy should released after function_foo() return-ed, my_resource should be nullptr;
    cout << "Is foo.my_resource released?: " << BoolToString(foo.my_resource == nullptr) << endl;
    cout << (*foo.my_resource) << endl;
    return 0;
}

Очевидно, что после вызова функции function_foo в основной функции неглубокая копия foo передается в function_foo в качестве аргумента, и эта неглубокая копия должна быть деструктурирована после завершения function_foo . После завершения работы функции поле my_resource в foo (объявленном в основной функции) все еще может быть проанализировано и получить значение 1234567. Я хотел бы знать, почему это так?

Моя идея состоит в том, что хотя ресурс памяти, на который указывает my_resource, освобождается при деструктуризации временного объекта, этот ресурс памяти не восстанавливается или не перезаписывается, поэтому к нему можно получить доступ в неправильном Кстати.
Компилятор сделал то, чего не должен был делать?

Кстати, я использую clang ++ в качестве компилятора, а среда разработки - это windows.

Компилировать: clang++ file.cxx -o file.exe запустить: ./file Результат:

Foo obj init, at: 0x61fdd8, my_resource at:0x1f1e90
function_foo() invoked
A Foo instance at: 0x61fdd0 is finalizing; my_resource: 0x1f1e90
is foo.my_resource released?: False
1234567
A Foo instance at: 0x61fdd8 is finalizing; my_resource: 0x1f1e90
c++
1
MuxAte 28 Фев 2021 в 14:25

2 ответа

Лучший ответ

Ресурс памяти освобожден, но это не значит, что он исчез! Он просто помечен как «свободная память», и в следующий раз, когда что-то в вашей программе попытается выделить память, ему может быть предоставлен этот кусок памяти. Так что да ... он все еще там ... пока ... но вам не следует полагаться на него, потому что вы не можете предсказать, что с ним произойдет в будущем.

C ++ не заботится о том, чтобы каким-то образом «заблокировать доступ» или даже просто «стереть» освобожденную память, потому что это потребует только циклов процессора без ощутимой выгоды. После того, как вы освободили память, вы все равно не должны ее трогать.

1
Vilx- 28 Фев 2021 в 11:30

После того, как функция завершила работу, поле my_resource в foo (объявленное в основной функции) все еще можно проанализировать и получить значение 1234567. Я хотел бы знать, почему это так?

Это неопределенное поведение, поэтому оно может сработать, если вам не повезет.

В типичных реализациях C ++ у этого есть хорошие шансы избежать сбоя, потому что выделение меньше страницы, и распределители не требуются для возврата памяти обратно в операционную систему. Это означает, что ваш процесс все еще может прочитать этот адрес.

Кроме того, компилятор не решил использовать адрес для чего-то еще, так что так получилось, что значение все еще там.

1
Acorn 28 Фев 2021 в 11:40