Pertanyaan Mengapa tidak std :: queue :: pop return value.?


Saya mengalami ini halaman tetapi saya tidak bisa mendapatkan alasan yang sama. Di sana disebutkan bahwa

"Lebih masuk akal untuk mengembalikan nilai sama sekali dan tidak perlu   klien menggunakan front () untuk memeriksa nilai di depan antrean "

Tetapi menginspeksi elemen dari depan () juga mensyaratkan elemen itu untuk disalin dalam lvalue. Misalnya di segmen kode ini

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);

/ * di sini sementara akan dibuat pada RHS yang akan ditetapkan untuk hasil, dan dalam kasus  jika kembali dengan referensi maka hasilnya akan diberikan tidak valid setelah operasi pop * /

result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();

di baris kelima cout objek pertama membuat salinan myqueue.front () kemudian menetapkan itu sebagai hasil. Jadi, apa bedanya, fungsi pop bisa saja melakukan hal yang sama.


75
2017-07-30 11:29


asal


Jawaban:


Jadi, apa bedanya, fungsi pop bisa saja melakukan hal yang sama.

Itu memang bisa melakukan hal yang sama. Alasannya tidak, adalah karena pop yang mengembalikan elemen yang muncul tidak aman di hadapan pengecualian (harus mengembalikan nilai dan dengan demikian membuat salinan).

Pertimbangkan skenario ini (dengan implementasi pop yang naif / dibuat-buat, untuk mengilustrasikan poin saya):

template<class T>
class queue {
    T* elements;
    std::size_t top_position;
    // stuff here
    T pop()
    {
        auto x = elements[top_position];
        // TODO: call destructor for elements[top_position] here
        --top_position;  // alter queue state here
        return x;        // calls T(const T&) which may throw
    }

Jika konstruktor salin dari T melempar saat kembali, Anda telah mengubah keadaan antrian (top_position dalam implementasi naif saya) dan elemen dihapus dari antrian (dan tidak dikembalikan). Untuk semua maksud dan tujuan (tidak peduli bagaimana Anda menangkap pengecualian dalam kode klien), elemen di bagian atas antrian hilang.

Implementasi ini juga tidak efisien dalam kasus ketika Anda tidak memerlukan nilai yang muncul (yaitu membuat salinan elemen yang tidak akan digunakan siapa pun).

Ini dapat diimplementasikan dengan aman dan efisien, dengan dua operasi terpisah (void pop dan const T& front()).


71
2017-07-30 11:42



Halaman yang Anda tautkan untuk menjawab pertanyaan Anda.

Untuk mengutip seluruh bagian yang relevan:

Orang mungkin bertanya-tanya mengapa pop () mengembalikan kekosongan, bukannya value_type. Yaitu, mengapa harus menggunakan front () dan pop () untuk memeriksa dan menghapus elemen di depan antrian, daripada menggabungkan keduanya dalam satu fungsi anggota? Bahkan, ada alasan bagus untuk desain ini. Jika pop () mengembalikan elemen depan, itu harus kembali dengan nilai daripada dengan referensi: kembali dengan referensi akan membuat pointer menjuntai. Kembali dengan nilai, bagaimanapun, tidak efisien: itu melibatkan setidaknya satu copy copy constructor panggilan. Karena tidak mungkin bagi pop () mengembalikan nilai sedemikian rupa sehingga menjadi efisien dan benar, lebih masuk akal untuk mengembalikan nilai sama sekali dan mengharuskan klien menggunakan front () untuk memeriksa nilai di bagian depan antrian.

C ++ dirancang dengan mempertimbangkan efisiensi, atas jumlah baris kode yang harus ditulis oleh programmer.


22
2017-07-30 11:39



pop tidak dapat mengembalikan referensi ke nilai yang dihapus, karena dihapus dari struktur data, jadi apa yang harus merujuk referensi? Itu bisa kembali dengan nilai, tetapi bagaimana jika hasil pop tidak disimpan di mana saja? Maka waktu terbuang untuk menyalin nilai yang tidak perlu.


3
2017-07-30 11:37



Dengan implementasi saat ini, ini valid:

int &result = myqueue.front();
std::cout << result;
myqueue.pop();

Jika pop akan mengembalikan referensi, seperti ini:

value_type& pop();

Maka kode berikut bisa macet, karena referensi tidak valid lagi:

int &result = myqueue.pop();
std::cout << result;

Di sisi lain, jika itu akan mengembalikan nilai secara langsung:

value_type pop();

Maka Anda perlu melakukan salinan agar kode ini berfungsi, yang kurang efisien:

int result = myqueue.pop();
std::cout << result;

2
2017-07-30 11:38



Anda benar-benar dapat melakukan ini:

std::cout << ' ' << myqueue.front();

Atau, jika Anda ingin nilai dalam variabel, gunakan referensi:

const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;

Di samping itu: kata-kata 'lebih masuk akal' adalah bentuk subjektif dari 'kami melihat ke dalam pola penggunaan dan menemukan lebih banyak kebutuhan untuk perpecahan'. (Yakinlah: bahasa C ++ tidak berkembang ringan ...)


0
2017-07-30 11:37



Saya pikir solusi terbaik adalah menambahkan sesuatu seperti

std::queue::pop_and_store(value_type& value);

dimana nilai akan menerima nilai yang muncul.

Keuntungannya adalah bahwa itu dapat diimplementasikan menggunakan operator penugasan pindah, sementara menggunakan depan + pop akan membuat salinan.


0
2018-06-28 19:27



Mulai dari Cx11 mungkin untuk mengarsipkan perilaku yang diinginkan menggunakan semantik gerakan. Seperti pop_and_move. Jadi copy constructor tidak akan dipanggil, dan kinerja akan bergantung pada konstruktor bergerak saja.


0
2018-01-24 01:56