Mengapa string :: bandingkan mengembalikan sebuah int?


102

Mengapa string::comparemengembalikan, intbukan jenis yang lebih kecil seperti shortatau char? Pemahaman saya adalah bahwa metode ini hanya mengembalikan -1, 0 atau 1.

Bagian kedua, jika saya merancang metode perbandingan yang membandingkan dua objek bertipe Foodan saya hanya ingin mengembalikan -1, 0 atau 1, akankah menggunakan shortatau charsecara umum merupakan ide yang bagus?

EDIT: Saya telah diperbaiki, string::comparetidak mengembalikan -1, 0, atau 1, itu sebenarnya mengembalikan nilai> 0, <0 atau 0. Terima kasih telah membuat saya tetap antri.

Sepertinya jawabannya kira-kira, tidak ada alasan untuk mengembalikan tipe yang lebih kecil daripada intkarena nilai yang dikembalikan adalah "rvalues" dan "rvalues" tersebut tidak diuntungkan karena lebih kecil dari tipe int (4 byte). Juga, banyak orang menunjukkan bahwa register dari sebagian besar sistem mungkin akan berukuran int, karena register ini akan diisi apakah Anda memberi mereka nilai 1, 2 atau 4 byte, tidak ada keuntungan nyata untuk mengembalikan nilai yang lebih kecil.

EDIT 2: Sebenarnya sepertinya ada overhead pemrosesan tambahan saat menggunakan tipe data yang lebih kecil seperti penyelarasan, masking, dll. Konsensus umum adalah bahwa tipe data yang lebih kecil ada untuk menghemat memori saat bekerja dengan banyak data, seperti pada kasus array.

Mempelajari sesuatu hari ini, terima kasih sekali lagi guys!


Saya pikir apa yang akan lebih baik adalah jika ada tipe yang lebih spesifik yang dapat digunakan untuk ini. Yang hanya berisi -1, 0 dan 1 dengan gaya Ada95.
Sachin Kainth

23
Dokumentasi untuk string::compare()Anda tautkan untuk menyatakan dengan jelas nilai kembaliannya adalah <0, 0, dan> 0 -tidak- -1, 0 dan 1.
Captain Obvlious

6
Apa keuntungan menggunakan shortatau charsebagai gantinya int? Kebanyakan arsitektur akan menyimpan nilai kembalian dari suatu fungsi dalam register, dan intakan muat dalam register seperti halnya shortatau char. Dan menggunakan charuntuk tipe numerik selalu merupakan ide yang buruk, terutama saat Anda perlu menjamin nilai yang ditandatangani ditangani dengan benar.
Cody Grey

7
Kapten Obvlious, nama dan komentarmu ... Tak ternilai harganya.
Cody Smith

2
Menggunakan charakan menjadi ide yang buruk, karena pemeriksaan kode untuk nilai kembalian jika kurang dari nol akan gagal pada platform yang chartidak ditandatangani.
milleniumbug

Jawaban:


113

Pertama, spesifikasinya adalah ia akan mengembalikan nilai kurang dari, sama dengan atau lebih besar dari 0, tidak harus -1atau 1. Kedua, nilai kembali adalah nilai r, tunduk pada promosi integral, jadi tidak ada gunanya mengembalikan sesuatu yang lebih kecil.

Dalam C ++ (seperti dalam C), setiap ekspresi adalah nilai r atau nilai l. Secara historis, istilah merujuk pada fakta bahwa nilai l muncul di sebelah kiri tugas, sedangkan nilai r hanya dapat muncul di sebelah kanan. Saat ini, pendekatan sederhana untuk tipe non-kelas adalah bahwa nilai l memiliki alamat dalam memori, nilai r tidak. Dengan demikian, Anda tidak dapat menggunakan alamat rvalue, dan cv-qualifier (kondisi "akses") tidak berlaku. Dalam istilah C ++, nilai r yang tidak memiliki tipe kelas adalah nilai murni, bukan objek. Nilai kembali dari suatu fungsi adalah nilai r, kecuali jika fungsi tersebut memiliki tipe referensi. (Tipe non-kelas yang cocok dengan register hampir selalu dikembalikan dalam register, misalnya, bukan di memori.)

Untuk tipe kelas, masalahnya sedikit lebih kompleks, karena Anda dapat memanggil fungsi anggota pada rvalue. Ini berarti bahwa nilai r sebenarnya harus memiliki alamat, untuk this penunjuk, dan dapat memenuhi syarat cv, karena kualifikasi cv berperan dalam penyelesaian beban berlebih. Akhirnya, C ++ 11 memperkenalkan beberapa perbedaan baru, untuk mendukung referensi rvalue; ini, juga, terutama berlaku untuk tipe kelas.

Promosi integral mengacu pada fakta bahwa ketika tipe integral yang lebih kecil dari an intdigunakan sebagai nilai r dalam ekspresi, dalam banyak konteks, mereka akan dipromosikan menjadi int. Jadi, meskipun saya memiliki variabel yang dideklarasikan short a, b;, dalam ekspresi tersebut a + b, keduanya adan bdipromosikan intsebelum penambahan terjadi. Demikian pula jika saya menulis a < 0, perbandingan dilakukan pada nilai a, dikonversikan ke int. Dalam praktiknya, ada sangat sedikit kasus di mana hal ini membuat perbedaan, setidaknya pada mesin pelengkap 2 di mana aritmatika integer membungkus (yaitu semua kecuali beberapa eksotik, hari ini — saya pikir mainframe Unisys adalah satu-satunya pengecualian yang tersisa). Namun, bahkan pada mesin yang lebih umum:

short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;

harus memberikan hasil yang berbeda: yang pertama setara dengan sizeof( short ), yang kedua sizeof( int )(karena promosi integral).

Kedua masalah ini secara formal ortogonal; rvalues ​​dan lvalues ​​tidak ada hubungannya dengan promosi integral. Kecuali ... promosi integral hanya berlaku untuk rvalues, dan sebagian besar (tapi tidak semua) kasus di mana Anda akan menggunakan rvalue akan menghasilkan promosi integral. Untuk alasan ini, sebenarnya tidak ada alasan untuk mengembalikan nilai numerik dalam sesuatu yang lebih kecil dari int. Bahkan ada alasan yang sangat bagus untuk tidak mengembalikannya sebagai tipe karakter. Operator yang kelebihan beban, seperti <<, sering berperilaku berbeda untuk tipe karakter, jadi Anda hanya ingin mengembalikan karakter sebagai tipe karakter. (Anda dapat membandingkan perbedaannya:

char f() { return 'a'; }
std::cout << f() << std::endl;      //  displays "a"
std::cout << f() + 0 << std::endl;  //  displays "97" on my machine

Perbedaannya adalah dalam kasus kedua, penambahan telah menyebabkan promosi integral terjadi, yang menghasilkan kelebihan beban yang berbeda <<untuk dipilih.


46
Alangkah baiknya jika Anda dapat menjelaskan lebih lanjut return values are rvalues, subject to integral promotiondalam jawaban Anda.
Alvin Wong

"nilai yang dikembalikan adalah nilai r ... jadi tidak ada gunanya mengembalikan sesuatu yang lebih kecil" SEPERTI ITU
masoud

1
@ AlvinWong: Lihat jawaban untuk Why are C character literals ints bukan chars? untuk mengetahui informasi latar belakang lainnya.
Jesse Good

Saya berharap saya dapat memberi ini +1 lagi, setelah penjelasan luar biasa yang Anda edit ditambahkan.
Cody Grey

Bagaimana jika ya signed char? Apakah itu berperilaku sama dengan yang ditandatangani char, atau apakah itu jenis yang berbeda?
pengguna541686

41

Itu disengaja agar tidak mengembalikan -1, 0 atau 1.

Itu memungkinkan (perhatikan ini bukan untuk string, tetapi ini berlaku sama untuk string)

int compare(int *a, int *b)
{
   return *a - *b;
}

yang jauh lebih praktis daripada:

int compare(int *a, int *b)
{
   if (*a == *b) return 0;
   if (*a > *b) return 1;
   return -1;
}

yang harus Anda lakukan [atau sesuatu seperti itu] jika Anda harus mengembalikan -1, 0 atau 1.

Dan ini juga berfungsi untuk jenis yang lebih kompleks:

class Date
{
    int year;
    int month;
    int day;
}

int compare(const Date &a, const Date &b)
{
   if (a.year != b.year) return a.year - b.year;
   if (a.month != b.month) return a.month - b.month;
   return a.day - b.day;
}

Dalam kasus string, kita bisa melakukan ini:

int compare(const std::string& a, const std::string& b)
{
   int len = min(a.length(), b.length());

   for(int i = 0; i < len; i++)
   {
      if (a[i] != b[i]) return a[i] - b[i];
   }
   // We only get here if the string is equal all the way to one of them
   // ends. If the length isn't equal, "longest" wins. 
   return a.length() - b.length();
}

8
compareFungsi pertama Anda bermasalah dengan overflow yang (untungnya) tidak berlaku sama jika dibutuhkan char*dan charlebih kecil dari int. Misalnya, jika *aadalah MAX_INTdan *badalah -1kemudian *a - *badalah UB, tetapi jika lagi memilih implementasi untuk menentukan perilakunya maka hasilnya hampir pasti negatif.
Steve Jessop

1
Masalah dengan contoh terakhir Anda: length()mengembalikan a size_t, yang mungkin lebih besar dari int
F'x

Ya, itu mungkin menjadi masalah jika string Anda lebih dari 2GB. Saya telah melakukan string panjang 1GB sebagai kasus uji untuk menyimpan sesuatu di fifo sekali. Tapi tentu, seseorang yang berurusan dengan string yang berisi MPEG yang dikodekan sebagai Base64 atau semacamnya mungkin mengalami masalah itu ...
Mats Petersson

@MatsPetersson ini lebih merupakan masalah mendasar, karena pertanyaannya adalah "mengapa ini mengembalikan int?"
F'x

Yah, saya yakin itu histeris - maksud saya alasan historis - dan mungkin agar kompatibel dengan strcmp / memcmp dan operasi jenis perbandingan lainnya.
Mats Petersson

25

int biasanya (artinya pada kebanyakan perangkat keras modern) adalah bilangan bulat dengan ukuran yang sama dengan bus sistem dan / atau register cpu, yang disebut kata mesin. Oleh karena itu int biasanya diteruskan lebih cepat daripada tipe yang lebih kecil, karena tidak memerlukan penyelarasan, masking, dan operasi lainnya.

Jenis yang lebih kecil ada terutama untuk memungkinkan pengoptimalan penggunaan RAM untuk array dan struct. Dalam kebanyakan kasus, mereka memperdagangkan beberapa siklus CPU (dalam bentuk operasi pengaturan) untuk penggunaan RAM yang lebih baik.

Kecuali Anda perlu memaksakan nilai kembalian Anda menjadi nomor bertanda tangan atau tidak bertanda tangan dari ukuran centain (char, pendek…) Anda lebih baik menggunakan int, itulah sebabnya perpustakaan standar melakukannya.


Cara yang bagus untuk menjelaskan sisi perangkat keras dengan cara yang masuk akal.
Ogre Mazmur33

10

Itu adalah C-isme.

Ketika C membutuhkan comparefungsi -type, mereka selalu mengembalikan int. C ++ baru saja meneruskannya (sayangnya).

Namun, mengembalikan secara intrealistis mungkin merupakan cara tercepat, karena umumnya ukuran register sistem yang digunakan. (Sengaja tidak jelas.)


1
Sebenarnya shortdan chardapat memberlakukan penalti kinerja, misalnya 255+7memiliki nilai yang berbeda untuk a chardan intsehingga implementasi yang benar tidak dapat serta merta menyimpan charkemana intsaja tanpa harus mengurus semantiknya. Penyusun tidak perlu mengoptimalkan inefisiensi yang ditimbulkan ini.
Jack Aidley

10

Metode ini tidak benar-benar mengembalikan integer di set { -1, 0, 1 }; itu sebenarnya bisa menjadi nilai integral apa pun .

Mengapa? Alasan utama yang dapat saya pikirkan adalah yang intseharusnya menjadi nilai "ukuran alami" untuk arsitektur; operasi pada nilai ukuran ini biasanya paling tidak secepat (dan dalam banyak kasus lebih cepat) daripada operasi pada nilai yang lebih kecil atau lebih besar. Jadi ini adalah kasus yang memungkinkan implementasi cukup kendur untuk menggunakan apa pun yang tercepat.


4

jika saya merancang metode perbandingan yang membandingkan dua objek bertipe Foo dan saya hanya ingin mengembalikan -1, 0 atau 1, apakah menggunakan short atau char umumnya menjadi ide yang bagus?

Ini akan menjadi ide yang bagus. Cara yang lebih baik adalah mengembalikan bool (jika hanya ingin membandingkan jika sama), atau enum (untuk informasi lebih lanjut):

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}

3
"Ini akan menjadi ide yang baik". Apakah Anda punya alasan untuk itu?
jrok

4

Misalkan beberapa orang mengubah kode dari C ke C ++. Mereka memutuskan untuk mengganti strcmpke string::compare.

Sejak strcmpkembali int, lebih mudah untuk string::comparekembali int, sebagai hadiah.


2

Mungkin untuk membuatnya bekerja lebih seperti strcmpyang juga memiliki kumpulan nilai pengembalian ini . Jika Anda ingin mem-port code, mungkin akan lebih intuitif untuk memiliki pengganti yang terbelah sedekat mungkin.

Juga, nilai kembalian tidak hanya -1, 0atau 1tetapi <0, 0atau >0.

Juga, seperti yang telah disebutkan karena pengembalian tunduk pada promosi integral , tidak masuk akal untuk membuatnya lebih kecil.


-1

karena nilai pengembalian boolean hanya dapat berupa dua nilai yang mungkin (benar, salah), dan fungsi perbandingan dapat mengembalikan tiga nilai yang mungkin (kurang dari, sama, lebih besar dari).

Memperbarui

Meskipun memang memungkinkan untuk mengembalikan short bertanda tangan, jika Anda benar - benar ingin mengimplementasikan fungsi bandingkan Anda sendiri, Anda dapat mengembalikan nilai nibble atau struct dengan dua boolean.


7
Tidak ada bagian dalam pertanyaan yang disebutkan tentang mengembalikan tipe Boolean. Bahkan, ia secara khusus mengusulkan shortdan charsebagai alternatif int.
Cody Gray
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.