Buku C ++ yang saya baca menyatakan bahwa ketika sebuah pointer dihapus menggunakan delete
operator, memori di lokasi yang ditunjuknya adalah "dibebaskan" dan dapat ditimpa. Ini juga menyatakan bahwa pointer akan terus menunjuk ke lokasi yang sama sampai dipindahkan atau diatur ke NULL
.
Namun dalam Visual Studio 2012; ini tampaknya tidak menjadi masalah!
Contoh:
#include <iostream>
using namespace std;
int main()
{
int* ptr = new int;
cout << "ptr = " << ptr << endl;
delete ptr;
cout << "ptr = " << ptr << endl;
system("pause");
return 0;
}
Ketika saya mengkompilasi dan menjalankan program ini saya mendapatkan output berikut:
ptr = 0050BC10
ptr = 00008123
Press any key to continue....
Jelas alamat yang ditunjuk oleh penunjuk berubah saat delete dipanggil!
Mengapa ini terjadi? Apakah ini ada hubungannya dengan Visual Studio secara khusus?
Dan jika delete dapat mengubah alamat yang ditunjuknya, mengapa tidak menghapus secara otomatis mengatur pointer ke NULL
alih-alih beberapa alamat acak?
sumber
Jawaban:
Saya perhatikan bahwa alamat yang disimpan
ptr
selalu ditimpa dengan00008123
...Ini tampak aneh, jadi saya melakukan sedikit penggalian dan menemukan posting blog Microsoft ini berisi bagian yang membahas "Sanitisasi pointer otomatis ketika menghapus objek C ++".
Tidak hanya menjelaskan apa yang Visual Studio lakukan dengan pointer setelah dihapus, itu juga menjawab mengapa mereka memilih TIDAK untuk mengaturnya
NULL
secara otomatis!"Fitur" ini diaktifkan sebagai bagian dari pengaturan "pemeriksaan SDL". Untuk mengaktifkan / menonaktifkannya buka: PROYEK -> Properti -> Properti Konfigurasi -> C / C ++ -> Umum -> pemeriksaan SDL
Untuk mengkonfirmasi ini:
Mengubah pengaturan ini dan menjalankan kembali kode yang sama menghasilkan output berikut:
"fitur" dalam tanda kutip karena dalam kasus di mana Anda memiliki dua petunjuk ke lokasi yang sama, memanggil delete hanya akan membersihkan SATU dari mereka. Yang lain akan dibiarkan menunjuk ke lokasi yang tidak valid ...
MEMPERBARUI:
Setelah 5 tahun pengalaman pemrograman C ++, saya menyadari bahwa seluruh masalah ini pada dasarnya adalah poin yang bisa diperdebatkan. Jika Anda seorang programmer C ++ dan masih menggunakan
new
dandelete
mengelola pointer mentah alih-alih menggunakan pointer pintar (yang menghindari seluruh masalah ini), Anda mungkin ingin mempertimbangkan perubahan jalur karier untuk menjadi seorang programmer C. ;)sumber
0x8123
bukan0
. Pointernya masih tidak valid, tetapi menyebabkan pengecualian ketika mencoba melakukan dereferensi (baik), dan tidak lulus pemeriksaan NULL (juga bagus, karena kesalahan untuk tidak melakukan itu). Di mana tempat untuk kebiasaan buruk? Ini benar-benar hanya sesuatu yang membantu Anda melakukan debug.Anda melihat efek samping dari
/sdl
opsi kompilasi. Dihidupkan secara default untuk proyek VS2015, memungkinkan pemeriksaan keamanan tambahan di luar yang disediakan oleh / gs. Gunakan Proyek> Properti> C / C ++> Umum> Pengaturan pemeriksaan SDL untuk mengubahnya.Mengutip dari artikel MSDN :
Perlu diingat bahwa pengaturan pointer yang dihapus ke NULL adalah praktik yang buruk ketika Anda menggunakan MSVC. Ini mengalahkan bantuan yang Anda dapatkan dari Debug Heap dan opsi / sdl ini, Anda tidak lagi dapat mendeteksi panggilan bebas / hapus yang tidak valid dalam program Anda.
sumber
delete
, Visual Studio akan membiarkan pointer kedua menunjuk ke lokasi aslinya yang sekarang tidak valid.Itu jelas informasi yang menyesatkan.
Ini jelas dalam spesifikasi bahasa.
ptr
tidak valid setelah panggilan kedelete
. Menggunakanptr
setelahdelete
d adalah penyebab perilaku tidak terdefinisi. Jangan lakukan itu. Lingkungan run time bebas untuk melakukan apa pun yang diinginkanptr
setelah panggilan kedelete
.Mengubah nilai pointer ke nilai lama apa pun ada dalam spesifikasi bahasa. Sejauh mengubahnya menjadi NULL, saya akan mengatakan, itu akan buruk. Program akan berperilaku lebih waras jika nilai pointer diatur ke NULL. Namun, itu akan menyembunyikan masalahnya. Ketika program dikompilasi dengan pengaturan optimisasi yang berbeda atau porting ke lingkungan yang berbeda, masalah kemungkinan akan muncul pada saat yang paling tidak tepat.
sumber
delete
dua kali pada pointer tidak akan menyebabkan masalah. Itu jelas tidak baik.NULL
tetapi juga pasti di luar ruang alamat proses akan memaparkan lebih banyak kasus daripada dua alternatif. Membiarkannya menggantung tidak akan menyebabkan segfault jika digunakan setelah dibebaskan; mengaturnya untukNULL
tidak akan menyebabkan segfault jikadelete
d lagi.Secara umum bahkan membaca (seperti yang Anda lakukan di atas, perhatikan: ini berbeda dari dereferencing) nilai-nilai pointer tidak valid (pointer menjadi tidak valid misalnya ketika Anda
delete
) adalah implementasi perilaku yang ditentukan. Ini diperkenalkan dalam CWG # 1438 . Lihat juga di sini .Harap perhatikan bahwa sebelum itu nilai pembacaan dari pointer yang tidak valid adalah perilaku yang tidak terdefinisi, jadi apa yang Anda miliki di atas akan menjadi perilaku yang tidak terdefinisi, yang berarti apa pun bisa terjadi.
sumber
[basic.stc.dynamic.deallocation]
: "Jika argumen yang diberikan ke fungsi deallokasi di perpustakaan standar adalah pointer yang bukan nilai null pointer, fungsi deallocation harus membatalkan alokasi penyimpanan yang dirujuk oleh pointer, menjadikan semua pointer yang tidak valid merujuk ke sembarang bagian dari penyimpanan yang tidak dapat dialokasikan "dan aturan dalam[conv.lval]
(bagian 4.1) yang mengatakan membaca (lvalue-> konversi nilai) setiap nilai pointer yang tidak valid adalah perilaku yang ditentukan implementasi.Saya percaya, Anda menjalankan semacam mode debug dan VS sedang berusaha untuk menunjuk kembali pointer Anda ke beberapa lokasi yang diketahui, sehingga upaya lebih lanjut untuk dereferensi itu dapat dilacak dan dilaporkan. Coba kompilasi / jalankan program yang sama dalam mode rilis.
Pointer biasanya tidak diubah di
delete
dalam demi efisiensi dan untuk menghindari memberikan gagasan keselamatan yang keliru. Mengatur hapus pointer ke nilai yang telah ditentukan sebelumnya tidak akan ada gunanya di sebagian besar skenario kompleks, karena pointer yang dihapus kemungkinan hanya satu dari beberapa yang menunjuk ke lokasi ini.Faktanya, semakin saya memikirkannya, semakin saya menemukan bahwa VS salah ketika melakukannya, seperti biasa. Bagaimana jika pointernya adalah const? Apakah masih akan mengubahnya?
sumber
Setelah menghapus pointer, memori yang ditunjukkannya mungkin masih valid. Untuk memanifestasikan kesalahan ini, nilai pointer diatur ke nilai yang jelas. Ini sangat membantu proses debugging. Jika nilainya diatur
NULL
, itu mungkin tidak pernah muncul sebagai bug potensial dalam aliran program. Jadi itu mungkin menyembunyikan bug saat Anda menguji nantiNULL
.Poin lain adalah, bahwa beberapa pengoptimal waktu berjalan dapat memeriksa nilai itu dan mengubah hasilnya.
Pada waktu sebelumnya MS mengatur nilainya
0xcfffffff
.sumber