Mengapa pointer tidak direkomendasikan saat pengkodean dengan C ++?


45

Saya membaca dari suatu tempat bahwa ketika menggunakan C ++ disarankan untuk tidak menggunakan pointer. Mengapa pointer adalah ide yang buruk ketika Anda menggunakan C ++. Untuk programmer C yang terbiasa menggunakan pointer, apa alternatif dan pendekatan yang lebih baik dalam C ++?


40
harap tautkan ke "suatu tempat". Konteksnya mungkin sangat relevan.

1
Semoga pertanyaan ini bermanfaat bagi Anda.
Garet Claborn

Sebagian besar jawaban ini merujuk pada menghindari kebocoran memori sebagai alasan utama. Saya tidak ingat kapan terakhir kali salah satu aplikasi kami mengalami masalah kebocoran memori meskipun menggunakan pointer. Jika Anda memiliki masalah kebocoran memori maka Anda tidak menggunakan alat yang tepat atau Anda tidak tahu apa yang Anda lakukan. Sebagian besar lingkungan pengembangan memiliki cara untuk secara otomatis memeriksa kebocoran yang terjadi. Saya pikir masalah kebocoran memori jauh lebih sulit untuk dilacak dalam bahasa sampah yang dikumpulkan karena kejadiannya jauh lebih halus dan Anda sering membutuhkan alat pihak ke-3 untuk melacak pelakunya. .
Dunk

1
Adding to @Dunk 's comment, sometimes built-in garbage collectors in higher-level languages simply do not work right. ActionScript 3's garbage collector doesn't, for instance. There's a bug in it right now that has to do with NetConnection instances disconnecting from the server (stackoverflow.com/questions/14780456/…), as well as an issue with there being multiple objects in a program that it will specifically refuse to ever collect ...
Panzercrisis

... ( adobe.com/devnet/actionscript/learning/as3-fundamentals/… - cari GCRoots are never garbage collected.dan paragraf dimulai dengan The MMgc is considered a conservative collector for mark/sweep.). Secara teknis ini adalah masalah di Adobe Virtual Machine 2, bukan AS3 itu sendiri, tetapi ketika Anda memiliki masalah seperti ini dalam bahasa tingkat yang lebih tinggi, yang pada dasarnya memiliki pengumpulan sampah, Anda sering tidak memiliki cara yang benar dalam bahasa untuk melakukan debug masalah ini sepenuhnya keluar dari program. ...
Panzercrisis

Jawaban:


58

Saya pikir mereka berarti Anda harus menggunakan pointer pintar daripada pointer biasa.

Dalam ilmu komputer, sebuah smart pointer adalah tipe data abstrak yang mensimulasikan sebuah pointer sambil memberikan fitur tambahan, seperti pengumpulan sampah otomatis atau pemeriksaan batas. Fitur-fitur tambahan ini dimaksudkan untuk mengurangi bug yang disebabkan oleh penyalahgunaan pointer sambil mempertahankan efisiensi. Pointer pintar biasanya melacak objek yang mereka tuju untuk tujuan manajemen memori.

Penyalahgunaan pointer adalah sumber utama bug: alokasi konstan, deallokasi dan referensi yang harus dilakukan oleh program yang ditulis menggunakan pointer menunjukkan risiko kebocoran memori akan terjadi. Pointer pintar mencoba untuk mencegah kebocoran memori dengan membuat sumber daya deallokasi otomatis: ketika pointer (atau yang terakhir dalam serangkaian pointer) ke objek dihancurkan, misalnya karena keluar dari ruang lingkup, objek yang runcing dihancurkan juga.

Dalam C ++ penekanannya akan pada pengumpulan sampah dan mencegah kebocoran memori (hanya untuk menyebutkan dua). Pointer adalah bagian mendasar dari bahasa, jadi tidak menggunakannya sama sekali tidak mungkin kecuali dalam program yang paling trival.


22
biasanya pengumpulan sampahnya tidak sepenuhnya dalam arti klasik, lebih banyak penghitungan referensi. Setidaknya dalam ptr pintar saya terbiasa ([boost | std] :: shared_ptr)
Doug T.

3
Jawaban ini sangat terbatas pada smart pointer, yang hanya merupakan aspek kecil dari masalahnya. Selain itu, smart pointer bukan pengumpulan sampah.
deadalnix

3
Juga RAII secara umum.
Klaim

3
Tidak, ini bukan yang dimaksudkan. Ini hanya satu aspek, dan bukan yang paling penting.
Konrad Rudolph

Saya pikir pointer cerdas adalah aspek yang paling penting, tetapi saya setuju ada banyak lainnya.
DeadMG

97

Karena saya orang yang menerbitkan polemik “jangan gunakan pointer f * cking” saya merasa bahwa saya harus berkomentar di sini.

Pertama-tama, sebagai polemik, ini jelas mewakili sudut pandang ekstrem. Jelas ada penggunaan sah dari pointer (mentah). Tetapi saya (dan banyak programmer C ++ profesional) berpendapat bahwa kasus-kasus ini sangat jarang. Tapi yang kami maksud adalah:

Pertama:

Pointer mentah harus dalam keadaan tidak memiliki memori.

Di sini, "memori sendiri" pada dasarnya berarti bahwa pada titik tertentu deletedisebut pada pointer itu (tetapi lebih umum dari itu). Pernyataan ini dapat dengan aman dianggap mutlak. Satu- satunya pengecualian adalah ketika menerapkan smart pointer Anda sendiri (atau strategi manajemen memori lainnya). Dan bahkan di sana Anda biasanya harus tetap menggunakan smart pointer di level rendah.

Alasan untuk ini cukup sederhana: pointer mentah yang memiliki memori memperkenalkan sumber kesalahan. Dan kesalahan ini banyak terjadi pada perangkat lunak yang ada: kebocoran memori dan penghapusan ganda - keduanya merupakan konsekuensi langsung dari kepemilikan sumber daya yang tidak jelas (tetapi berlawanan arah).

Masalah ini dapat sepenuhnya dihilangkan, hampir tanpa biaya, dengan hanya menggunakan pointer pintar bukan pointer mentah (peringatan: ini masih membutuhkan pemikiran, tentu saja; pointer bersama dapat menyebabkan siklus dan dengan demikian sekali lagi ke kebocoran memori - tetapi ini dengan mudah dihindari).

Kedua:

Sebagian besar penggunaan pointer di C ++ tidak perlu.

Tidak seperti bahasa lain, C ++ memiliki dukungan yang sangat kuat untuk semantik nilai dan tidak perlu tipuan pointer. Ini tidak segera terwujud - secara historis, C ++ ditemukan untuk memfasilitasi orientasi objek yang mudah dalam C, dan sangat bergantung pada pembuatan grafik objek yang dihubungkan oleh pointer. Tetapi dalam C ++ modern, paradigma ini jarang merupakan pilihan terbaik, dan idiom C ++ modern seringkali tidak memerlukan pointer sama sekali . Mereka beroperasi pada nilai daripada pointer.

Sayangnya, pesan ini masih belum tertangkap di sebagian besar komunitas pengguna C ++. Akibatnya, sebagian besar kode C ++ yang ditulis masih dikotori dengan pointer berlebihan yang membuat kode kompleks, lambat dan rusak / tidak dapat diandalkan.

Untuk seseorang yang tahu C yang modern ++, jelas bahwa Anda sangat jarang perlu setiap pointer (baik pintar atau mentah; kecuali bila menggunakan mereka sebagai iterator). Kode yang dihasilkan lebih pendek, kurang kompleks, lebih mudah dibaca, seringkali lebih efisien dan lebih dapat diandalkan.


5
Huh ... ini seharusnya benar-benar menjadi jawaban dengan 30+ upvotes ... terutama untuk poin kedua. Pointer bahkan jarang diperlukan dalam C ++ modern.
Charles Salvia

1
bagaimana dengan misalnya. Objek Gui memiliki banyak objek dokumen. Ini memiliki ini sebagai pointer baik sehingga kelas dapat maju dinyatakan (menghindari kompilasi ulang) dan agar objek dapat diinisialisasi ketika dibuat (dengan yang baru) daripada dibuat pada stack dalam beberapa keadaan kosong dan kemudian diarsipkan nanti? Ini sepertinya penggunaan pointer yang valid - bukankah seharusnya semua objek yang dienkapsulasi berada di heap?
Martin Beckett

4
Objek @Martin GUI adalah salah satu kasus di mana grafik objek pointer memang solusi terbaik. Tetapi dekrit terhadap petunjuk mentah yang memiliki memori masih berlaku. Baik menggunakan pointer bersama di seluruh atau mengembangkan model kepemilikan yang tepat dan hanya memiliki hubungan yang lemah (= tidak memiliki) antara kontrol melalui pointer mentah.
Konrad Rudolph

1
@ VF1 std::unique_ptr. Kenapa tidak ptr_vec? Tetapi biasanya vektor nilai dengan masih akan bertukar lebih cepat (terutama dengan memindahkan semantik).
Konrad Rudolph

1
@gaazkam Tidak ada yang memaksa Anda untuk hanya menggunakan kontainer standar. Boost misalnya memiliki implementasi peta dengan dukungan untuk tipe yang tidak lengkap. Solusi lain adalah dengan menggunakan tipe erasure; boost::variantdengan recursive_wrappermungkin solusi favorit saya untuk mewakili DAG.
Konrad Rudolph

15

Hanya karena ada abstraksi yang tersedia untuk Anda yang menyembunyikan aspek yang lebih temperamental menggunakan pointer, seperti akses ke memori mentah dan membersihkan setelah alokasi Anda. Dengan pointer cerdas, kelas wadah, dan pola desain seperti RAII, kebutuhan untuk menggunakan pointer mentah berkurang. Yang mengatakan, seperti abstraksi apa pun, Anda harus memahami bagaimana mereka benar-benar bekerja sebelum bergerak melampaui mereka.


11

Relatif sederhana, mentalitas C adalah "Punya masalah? Gunakan pointer". Anda dapat melihat ini dalam string C, pointer fungsi, pointer-sebagai-iterator, pointer-to-pointer, void pointer- bahkan pada hari-hari awal C ++ dengan pointer anggota.

Tetapi dalam C ++ Anda bisa menggunakan nilai untuk banyak atau semua tugas ini. Perlu abstraksi fungsi? std::function. Ini adalah nilai yang berfungsi. std::string? Ini sebuah nilai, itu sebuah string. Anda dapat melihat pendekatan serupa di seluruh C ++. Ini membuat menganalisis kode jauh lebih mudah bagi manusia dan penyusun.


Di C ++: Punya masalah? Gunakan pointer. Sekarang Anda memiliki 2 masalah ...
Daniel Zazula

10

Salah satu alasannya adalah penerapan pointer yang terlalu luas. Mereka dapat digunakan untuk iterasi di atas wadah, untuk menghindari penyalinan benda besar saat beralih ke fungsi, manajemen seumur hidup non-sepele, mengakses ke tempat-tempat acak dalam memori, dll. Dan begitu Anda menggunakannya untuk satu tujuan, fitur-fitur lainnya akan tersedia segera secara mandiri dengan sengaja.

Pemilihan alat untuk tujuan yang tepat membuat kode lebih mudah dan maksud lebih terlihat - iterator untuk iterasi, pointer pintar untuk manajemen seumur hidup, dll.


3

Selain alasan yang sudah disebutkan, ada alasan yang jelas: optimisasi yang lebih baik. Analisis aliasing terlalu rumit dalam hal aritmatika penunjuk, sedangkan referensi mengisyaratkan pengoptimal, sehingga analisis aliasing jauh lebih dalam dimungkinkan jika hanya referensi yang digunakan.


2

Selain risiko kebocoran memori yang dinyatakan oleh pointer @jmquigley dan aritmatika pointer dapat dianggap bermasalah karena pointer dapat menunjukkan di mana-mana dalam memori yang menyebabkan "sulit menemukan bug" dan "kerentanan keamanan".

Itulah sebabnya mereka hampir ditinggalkan di C # dan Java.


Berharap mereka tidak "dihapus" di C #. Jawaban ini buruk, memiliki ejaan yang mengerikan, dan pernyataan tidak akurat yang mengerikan.
Ramhound

1
Mereka hampir ditinggalkan. Saya minta maaf karena tidak menjadi penutur asli.
k3b

1
Hei, kami bisa membantu mengeja. Apakah Anda bermaksud mengatakan mengharapkan atau kecuali?
DeveloperDon

1
Hampir ditinggalkan di C #, Anda masih dapat mengaktifkan pointer dengan menentukan unsafekata kunci
linquize

-1

C ++ mendukung sebagian besar C , fitur, plus Objek dan Kelas. C sudah memiliki petunjuk dan hal-hal lainnya.

Pointer adalah teknik yang sangat berguna, yang dapat dikombinasikan dengan Orientasi Objek, dan C ++ mendukungnya. Tapi, teknik ini, sulit diajarkan dan sulit dipahami, dan, sangat mudah menyebabkan kesalahan yang tidak diinginkan.

Banyak bahasa pemrograman baru berpura-pura tidak menggunakan pointer dengan objek, seperti Java, .NET, Delphi, Vala, PHP, Scala. Tapi, pointer masih digunakan, "di belakang layar". Teknik "pointer tersembunyi" ini disebut "referensi".

Bagaimanapun, saya menganggap pointer sebagai Pola Pemrograman, sebagai cara yang valid untuk memecahkan masalah tertentu, serta Pemrograman Berorientasi Objek tidak.

Pengembang lain mungkin memiliki pendapat berbeda. Tapi, saya sarankan siswa dan programmer belajar bagaimana:

(1) Gunakan pointer tanpa objek

(2) objek tanpa pointer

(3) pointer eksplisit ke objek

(4) pointer "tersembunyi" ke objek ( referensi AKA ) ;-)

Dalam urutan itu.

Kalaupun sulit untuk diajar, dan sulit untuk dipelajari. Obyek Pascal (Delphi, FreePascal, lainnya) dan C++(bukan Java atau C #) dapat digunakan untuk tujuan tersebut.

Dan, nantinya, programmer pemula, dapat pindah ke "pointer tersembunyi ke objek" bahasa pemrograman seperti: Java, C #, PHP Berorientasi Objek, dan lainnya.


19
C ++ jauh lebih banyak daripada "C with Classes" yang awalnya.
David Thornley

Mengapa Anda memasukkan C ++ dan C ke dalam tanda kutip udara? Dan "tersembunyi", "referensi" dan yang lainnya? Apakah Anda seorang "salesman" dan tidak berpartisipasi dalam "pemrograman"?
phresnel

Saya harus menempatkan mereka dalam huruf tebal. Kutipan dapat digunakan untuk menyoroti tetapi juga sebaliknya
umlcat

-6

Berbicara tentang VC6, ketika Anda melemparkan pointer kelas (yang Anda instantiate) ke dalam variabel (misalnya DWORD), bahkan jika pointer ini lokal Anda dapat mengakses kelas atas semua fungsi yang menggunakan tumpukan yang sama. Kelas instantiated didefinisikan sebagai lokal tetapi sebenarnya tidak. Sejauh yang saya tahu, alamat variabel, struktur, atau kelas apa pun adalah unik sepanjang umur kelas hosting.

Contoh:

class MyClass1 {
    public:
        void A (void);
        void B (void);
        void C (void);
    private:
        DWORD dwclass;
};

class MyClass2 {
    public:
        int C (int i);
};

void MyClass1::A (void) {
    MyClass2 *myclass= new MyClass2;
    dwclass=(DWORD)myclass;
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    int i = myclass->C(0); // or int i=((MyClass2 *)dwclass)->C(0);
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    delete myclass;
}

EDIT Itu bagian sangat kecil dari kode asli. Kelas CSRecodset hanya kelas casting CXdbRecordset, di mana semua kode sebenarnya berada. Dengan melakukan itu, saya dapat membiarkan pengguna mengambil manfaat dari apa yang saya tulis tanpa kehilangan hak saya. Saya tidak berpura-pura menunjukkan bahwa mesin basis data saya profesional tetapi benar-benar berfungsi.

//-------------------------------------
class CSRecordSet : public CSObject
//-------------------------------------
{
public:
    CSRecordSet();
    virtual ~CSRecordSet();
    // Constructor
    bool Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef);
    //Open, find, close
    int OpenRst(bool bReadBlanks=0,bool bCheckLastSql=0,bool bForceLoad=0,bool bMessage=1);     // for a given SQL
    int FindRecord(bool bNext);         // for a given SQL
    // TABLE must be ordered by the same fields that will be seek
    bool SeekRecord(int nFieldIndex, char *key, int length=0);  // CRT bsearch
    bool SeekRecord(int nFieldIndex, long key);     
    bool SeekRecord(int nFieldIndex, double key, int decimals);     
    bool SeekRecord(XSEK *SEK);     
    bool DeleteRecord(void);
    bool Close(void);
    // Record Position:
    bool IsEOF(void);           // pointer out of bound
    bool IsLAST(void);          // TRUE if last record
    bool IsBOF(void);           // pointer out of bound
    bool IsOpen(void);
    bool Move(long lRows);      // returns FALSE if out of bound
    void MoveNextNotEof(void);  // eof is tested
    void MoveNext(void);        // eof is not tested
    void MovePrev(void);        // bof is tested
    void MoveLast(void);
    void MoveFirst(void);
    void SetAbsolutePosition(long lRows);
    long GetAbsolutePosition(void);
    void GoToLast(void); // Restore position after a Filter
    // Table info
    long GetRecordCount(void);
    int GetRstTableNumber(void);
    int GetRecordLength(void); //includes stamp (sizeof char)
    int GetTableType(void);
    // Field info
    int GetFieldCount(void);
    void GetFieldName(int nFieldIndex, char *pbuffer);
    int GetFieldIndex(const char *sFieldName);
    int GetFieldSize(int nFieldIndex);
    int GetFieldDGSize(int nFieldIndex); // String size (i.e. dg_Boolean)
    long GetRecordID(void);
    int GetStandardFieldCount(void);
    bool IsMemoFileTable(void);
    bool IsNumberField(int nFieldIndex);
    int GetFieldType(int nFieldIndex);
    // Read Field value
    bool GetFieldValue(int nFieldIndex, XdbVar& var);
    bool GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer);
    char *GetMemoField(int nMemoFieldIndex, char *pbuffer, int buf_size);
    bool GetBinaryField(unsigned char *buffer,long *buf_size);
    // Write Field value
    void Edit(void); // required
    bool SetFieldValue(int nFieldIndex, XdbVar& var);
    bool SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer);
    bool Update(void); // required
    // pointer to the same lpSql
    LPXSQL GetSQL(void);
};

//---------------------------------------------------
CSRecordSet::CSRecordSet(){
//---------------------------------------------------
    pClass |= (CS_bAttach);
}
CSRecordSet::~CSRecordSet(){
    if(pObject) delete (CXdbRecordset*)pObject;
}
bool CSRecordSet::Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef){
    CXdbQueryDef *qr=(CXdbQueryDef*)pQueryDef->GetObject();
    CXdbTables *db=(CXdbTables*)pDataBase->GetObject();
    CXdbRecordset *rst = new CXdbRecordset(db,qr);
    if(rst==NULL) return 0;
    pObject = (unsigned long) rst;
    return 1;
}
bool CSRecordSet::Close(void){
    return ((CXdbRecordset*)pObject)->Close();
}
int CSRecordSet::OpenRst(bool bReadBlanks,bool bCheckLastSql,bool bForceLoad, bool bMessage){
    unsigned long dw=0L;
    if(bReadBlanks) dw|=SQL_bReadBlanks;
    if(bCheckLastSql) dw|=SQL_bCheckLastSql;
    if(bMessage) dw|=SQL_bRstMessage;
    if(bForceLoad) dw|=SQL_bForceLoad;

    return ((CXdbRecordset*)pObject)->OpenEx(dw);
}
int CSRecordSet::FindRecord(bool bNext){
    return ((CXdbRecordset*)pObject)->FindRecordEx(bNext);
}
bool CSRecordSet::DeleteRecord(void){
    return ((CXdbRecordset*)pObject)->DeleteEx();
}
bool CSRecordSet::IsEOF(void){
    return ((CXdbRecordset*)pObject)->IsEOF();
}
bool CSRecordSet::IsLAST(void){
    return ((CXdbRecordset*)pObject)->IsLAST();
}
bool CSRecordSet::IsBOF(void){
    return ((CXdbRecordset*)pObject)->IsBOF();
}
bool CSRecordSet::IsOpen(void){
    return ((CXdbRecordset*)pObject)->IsOpen();
}
bool CSRecordSet::Move(long lRows){
    return ((CXdbRecordset*)pObject)->MoveEx(lRows);
}
void CSRecordSet::MoveNextNotEof(void){
    ((CXdbRecordset*)pObject)->MoveNextNotEof();
}
void CSRecordSet::MoveNext(void){
    ((CXdbRecordset*)pObject)->MoveNext();
}
void CSRecordSet::MovePrev(void){
    ((CXdbRecordset*)pObject)->MovePrev();
}
void CSRecordSet::MoveLast(void){
    ((CXdbRecordset*)pObject)->MoveLast();
}
void CSRecordSet::MoveFirst(void){
    ((CXdbRecordset*)pObject)->MoveFirst();
}
void CSRecordSet::SetAbsolutePosition(long lRows){
    ((CXdbRecordset*)pObject)->SetAbsolutePosition(lRows);
}
long CSRecordSet::GetAbsolutePosition(void){
    return ((CXdbRecordset*)pObject)->m_AbsolutePosition;
}
long CSRecordSet::GetRecordCount(void){
    return ((CXdbRecordset*)pObject)->GetRecordCount();
}
int CSRecordSet::GetFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetFieldCount();
}
int CSRecordSet::GetRstTableNumber(void){
    return ((CXdbRecordset*)pObject)->GetRstTableNumber();
}
void CSRecordSet::GetFieldName(int nFieldIndex, char *pbuffer){
    ((CXdbRecordset*)pObject)->GetFieldName(nFieldIndex,pbuffer);
}
int CSRecordSet::GetFieldIndex(const char *sFieldName){
    return ((CXdbRecordset*)pObject)->GetFieldIndex(sFieldName);
}
bool CSRecordSet::IsMemoFileTable(void){
    return ((CXdbRecordset*)pObject)->IsMemoFileTable();
}
bool CSRecordSet::IsNumberField(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->IsNumberField(nFieldIndex);
}
bool CSRecordSet::GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer){
    return ((CXdbRecordset*)pObject)->GetFieldValueIntoBuffer(nFieldIndex,pbuffer);
}
void CSRecordSet::Edit(void){
    ((CXdbRecordset*)pObject)->Edit();
}
bool CSRecordSet::Update(void){
    return ((CXdbRecordset*)pObject)->Update();
}
bool CSRecordSet::SetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->SetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer){
    return ((CXdbRecordset*)pObject)->SetFieldValueFromBuffer(nFieldIndex,pbuffer);
}
bool CSRecordSet::GetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->GetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SeekRecord(XSEK *SEK){
    return ((CXdbRecordset*)pObject)->TableSeek(SEK);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,char *key, int length){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,key,length);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,long i){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,i);
}
bool CSRecordSet::SeekRecord(int nFieldIndex, double d, int decimals)
{
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,d,decimals);
}
int CSRecordSet::GetRecordLength(void){
    return ((CXdbRecordset*)pObject)->GetRecordLength();
}
char *CSRecordSet::GetMemoField(int nMemoFieldIndex,char *pbuffer, int BUFFER_SIZE){
    return ((CXdbRecordset*)pObject)->GetMemoField(nMemoFieldIndex,pbuffer,BUFFER_SIZE);
}
bool CSRecordSet::GetBinaryField(unsigned char *buffer,long *buf_size){
    return ((CXdbRecordset*)pObject)->GetBinaryField(buffer,buf_size);
}
LPXSQL CSRecordSet::GetSQL(void){
    return ((CXdbRecordset*)pObject)->GetSQL();
}
void CSRecordSet::GoToLast(void){
    ((CXdbRecordset*)pObject)->GoToLast();
}
long CSRecordSet::GetRecordID(void){
    return ((CXdbRecordset*)pObject)->GetRecordID();
}
int CSRecordSet::GetStandardFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetStandardFieldCount();
}
int CSRecordSet::GetTableType(void){
    return ((CXdbRecordset*)pObject)->GetTableType();
}
int CSRecordSet::GetFieldType(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldType(nFieldIndex);
}
int CSRecordSet::GetFieldDGSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldDGSize(nFieldIndex);
}
int CSRecordSet::GetFieldSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldSize(nFieldIndex);
}

EDIT: diminta oleh DeadMG:

void nimportequoidumomentquecaroule(void) {

    short i = -4;
    unsigned short j=(unsigned short)i;

}

1
Deskripsi ini dapat ditingkatkan secara signifikan oleh beberapa kode untuk menggambarkan apa yang Anda gambarkan. Saya memiliki perasaan bahwa itu terkait dengan pertanyaan asli, tetapi jika Anda memperingatkan kami tentang bahaya dalam skenario ini, itu akan membantu menguraikan topik si penanya.
PengembangDon

1
Yang dilemparkan ke DWORDkasar dan mungkin salah (DWORD tidak cukup lebar untuk menahan pointer). Jika Anda memerlukan pointer yang tidak diketik, gunakan void*- tetapi ketika Anda membutuhkannya di C ++, Anda sering mendapatkan masalah desain dalam kode yang harus Anda perbaiki.
Mat

Salvador, saya pikir Anda mencoba untuk mengatakan sesuatu tentang VC6 dan bagaimana ia memiliki penanganan pointer yang tidak biasa dan tidak terduga. Contoh tersebut dapat diuntungkan dengan komentar, dan jika Anda melihat peringatan dari kompiler, mereka mungkin informatif sehubungan dengan menghubungkan jawaban Anda dengan pertanyaan tersebut.
Pengembang

@Mat Contoh itu untuk OS 32 bit dan VC6 ++ compiler.
Salvador

6
Berbicara tentang kode buruk di kompiler yang benar-benar kuno? Tidak, terima kasih.
DeadMG
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.