Saya menggunakan std :: antrian untuk mengimplementasikan kelas JobQueue. (Pada dasarnya kelas ini memproses setiap pekerjaan dengan cara FIFO). Dalam satu skenario, saya ingin menghapus antrian dalam satu kesempatan (hapus semua pekerjaan dari antrian). Saya tidak melihat metode yang jelas tersedia di std :: kelas antrian.
Bagaimana cara saya menerapkan metode yang jelas untuk kelas JobQueue secara efisien?
Saya punya satu solusi sederhana untuk muncul dalam satu lingkaran tetapi saya mencari cara yang lebih baik.
//Clears the job queue
void JobQueue ::clearJobs()
{
// I want to avoid pop in a loop
while (!m_Queue.empty())
{
m_Queue.pop();
}
}
deque
mendukung clearJawaban:
Ungkapan umum untuk membersihkan wadah standar adalah menukar dengan versi kosong dari wadah:
Ini juga satu-satunya cara untuk benar-benar membersihkan memori yang tersimpan di dalam beberapa wadah (std :: vector)
sumber
std::queue<int>().swap(q)
. Dengan idiom copy dan swap, semua ini harus setara denganq = std::queue<int>()
.std::queue<int>().swap(q)
setara dengan kode di atas,q = std::queue<int>()
tidak perlu sama. Karena tidak ada transfer kepemilikan dalam penugasan memori yang dialokasikan beberapa wadah (seperti vektor) mungkin hanya memanggil destruktor dari elemen yang dimiliki sebelumnya dan mengatur ukuran (atau operasi setara dengan pointer yang disimpan) tanpa benar-benar melepaskan memori.queue
tidak memilikiswap(other)
metode, jadiqueue<int>().swap(q)
jangan kompilasi. Saya pikir Anda harus menggunakan obat generikswap(a, b)
.Ya - sedikit kesalahan kelas antrian, IMHO. Inilah yang saya lakukan:
sumber
swap
"lebih efektif"q1.swap(queue<int>());
q1=queue<int>();
keduanya lebih pendek, dan lebih jelas (Anda tidak benar - benar berusaha.swap
, Anda mencoba.clear
).q1 = {}
cukupqueue<T>
Konstruktor default cocok dengan daftar argumen kosong{}
dan implisit, sehingga disebut, kemudianq1.operator=(queue<T>&&)
mengkonsumsi yang baru dibuatqueue
Penulis topik bertanya bagaimana menghapus antrian "efisien", jadi saya menganggap dia ingin kompleksitas yang lebih baik daripada O linear (ukuran antrian) . Metode yang dilayani oleh David Rodriguez , anon memiliki kompleksitas yang sama: menurut referensi STL,
operator =
memiliki kompleksitas O (ukuran antrian) . IMHO karena setiap elemen antrian dicadangkan secara terpisah dan tidak dialokasikan dalam satu blok memori besar, seperti dalam vektor. Jadi untuk menghapus semua memori, kita harus menghapus setiap elemen secara terpisah. Jadi cara paling mudah untuk menghapusstd::queue
adalah satu baris:sumber
O(n^2)
algoritma dari suatuO(n)
algoritma jika konstanta pada operasi linier membuatnya lebih lambat dari kuadrat untuk semuan < 2^64
, kecuali saya punya alasan kuat untuk percaya saya harus mencari ruang alamat IPv6 atau beberapa masalah khusus lainnya. Kinerja pada kenyataannya lebih penting bagi saya daripada kinerja pada batasnya.Rupanya, ada dua cara yang paling jelas untuk dihapus
std::queue
: bertukar dengan objek kosong dan penugasan ke objek kosong.Saya akan menyarankan menggunakan tugas karena hanya lebih cepat, lebih mudah dibaca, dan tidak ambigu.
Saya mengukur kinerja menggunakan kode sederhana berikut dan saya menemukan bahwa bertukar dalam versi C ++ 03 bekerja 70-80% lebih lambat daripada penugasan ke objek kosong. Namun, dalam C ++ 11 tidak ada perbedaan kinerja. Bagaimanapun, saya akan pergi dengan tugas.
sumber
Di C ++ 11 Anda dapat menghapus antrian dengan melakukan ini:
sumber
Anda bisa membuat kelas yang mewarisi dari antrian dan menghapus wadah yang mendasarinya secara langsung. Ini sangat efisien.
Mungkin implementasi Anda juga memungkinkan objek Antrian Anda (di sini
JobQueue
) untuk mewarisistd::queue<Job>
alih-alih memiliki antrian sebagai variabel anggota. Dengan cara ini Anda akan memiliki akses langsung kec.clear()
dalam fungsi anggota Anda.sumber
Dengan asumsi Anda
m_Queue
mengandung bilangan bulat:Jika tidak, jika berisi mis pointer ke
Job
objek, maka:Dengan cara ini Anda menukar antrian kosong dengan Anda
m_Queue
, sehinggam_Queue
menjadi kosong.sumber
Saya lebih suka tidak mengandalkan
swap()
atau mengatur antrian ke objek antrian yang baru dibuat, karena elemen antrian tidak dihancurkan dengan benar. Memanggilpop()
memanggil destruktor untuk objek elemen masing-masing. Ini mungkin bukan masalah dalam<int>
antrian tetapi mungkin sangat baik memiliki efek samping pada antrian yang berisi objek.Oleh karena itu loop dengan
while(!queue.empty()) queue.pop();
tampaknya sayangnya menjadi solusi paling efisien setidaknya untuk antrian yang berisi objek jika Anda ingin mencegah kemungkinan efek samping.sumber
swap()
atau tugas memanggil destruktor pada antrian sekarang-mati, yang memanggil destruktor semua objek pada antrian. Sekarang, jika antrian Anda memiliki objek yang sebenarnya pointer, itu masalah yang berbeda - tetapi sederhanapop()
tidak akan membantu Anda di sana.Saya melakukan ini (Menggunakan C ++ 14):
Cara ini berguna jika Anda memiliki jenis antrian non-sepele yang Anda tidak ingin buat alias / typedef. Saya selalu memastikan untuk meninggalkan komentar seputar penggunaan ini, untuk menjelaskan kepada programmer yang tidak curiga bahwa ini tidak gila, dan dilakukan sebagai pengganti
clear()
metode yang sebenarnya .sumber
myqueue = { };
akan bekerja dengan baik.Menggunakan
unique_ptr
mungkin OK.Anda kemudian mengatur ulang untuk mendapatkan antrian kosong dan melepaskan memori antrian pertama. Adapun kompleksitasnya? Saya tidak yakin - tetapi kira itu O (1).
Kode yang mungkin:
sumber
Pilihan lain adalah menggunakan peretasan sederhana untuk mendapatkan wadah yang mendasarinya
std::queue::c
dan memanggilnyaclear
. Anggota ini harus hadirstd::queue
sesuai standar, tetapi sayangnyaprotected
. Retasan di sini diambil dari jawaban ini .sumber