2015-11-26 14 views
15

Die Aktien Beispiel einer Referenzqualifizierten Memberfunktion scheint so etwas zu sein:const-Referenz qualifizierte Memberfunktion

#include <stdio.h> 
#include <stdexcept> 
#include <string> 

// Easy access to literals 
using namespace std::literals; 

// File wrapper 
class File { 
    private: 
    // The wrapped file 
    FILE *_file; 
    public: 
    File(const char *name) : 
     _file(fopen(name, "r")) { 
     // unable to open the file? 
     if (!_file) throw std::runtime_error{ "Unable to open file: "s + name }; 
    } 
    ~File() { 
     fclose(_file); 
    } 

    // Convert to the underlying wrapped file 
    operator FILE *() & { 
     return _file; 
    } 

    // TODO: Member functions for working with the file 
}; 

Diese gut funktioniert. Es ist nicht möglich, den zugrunde liegenden FILE-Zeiger direkt von einem unbenannten temporären Objekt abzurufen. Wenn wir jedoch den Casting-Operator auch const-qualifiziert machen, scheint das nicht mehr zu funktionieren.

Verschiedene Compiler einfach schlucken es ohne Beschwerde, obwohl es eine sehr nützliche Idee ist. Nehmen wir zum Beispiel die Memberfunktion std :: string :: c_str(). Sie denken, es sollte Referenz-qualifiziert sein (weil Sie sonst einen ungültigen Zeiger haben), aber es ist nicht.

Ist das ein Loch in der C++ 11-Norm? Fehle ich hier etwas?

+4

Kannst du den Code ein wenig dichter machen? Es ist mehr als eine Seite für 2 Methoden – user463035818

+2

Die 'c_str()' ist nützlich in einem Parameter, auch wenn es eine temporäre ist. In 'f (g(). C_str());' die begrenzte Lebensdauer kann in Ordnung sein. –

+0

Nebenbei: Nicht alle r-Wert-Referenzen sind Provisorien. – Hurkyl

Antwort

16

Ein temporäres Objekt kann an ein const& qualifiziertes Objekt gebunden werden, und das ref-Qualifikationsmerkmal qualifiziert das implizit übergebene Objekt effektiv (*this). Wenn Sie Aufrufe von Provisorien verhindern, aber L-Werte zulassen möchten, können Sie die Rvalue-Referenzüberladung = delete implementieren und die Lvalue-Version implementieren. Mit const qualifizierter Referenz-Qualifikation für beiden Betreiber benötigt nur eine implementiert und eine = delete d Umsetzung:

class File { 
    // ... 
    FILE* _file; 
public: 
    operator FILE*() const&& = delete; 
    operator FILE*() const& { return this->_file; } 
    // ... 
}; 

Der Netto-Effekt ist, dass Sie die Konvertierung verwenden können nur für Objekte, zu denen Sie einen L-Wert gehen:

int main() { 
    File  f; 
    File const cf{}; 

    FILE* fp = f;    // OK 
    FILE* cfp = cf;   // OK 
    FILE* tfp = File();  // ERROR: conversion is deleted 
    FILE* mfp = std::move(cf); // ERROR: conversion is deleted 
} 
+0

Dies scheint die Lösung zu sein. Ich denke nicht, dass es notwendig ist, die nicht-konstante Operatorfunktion einzuschließen. Ich habe kein unerwünschtes Verhalten ohne es zu bekommen. –

+6

Statt '&& = delete' könnte man' const && = delete' verwenden, sonst würde ein const rvalue an eine 'const & 'overload –

+0

@PiotrSkotnicki binden: danke - mir war dieses Loop-Loch nicht bekannt. Ich habe die Antwort entsprechend aktualisiert. –

Verwandte Themen