Pytanie Wdrażanie równoważnika C ++ przy użyciu instrukcji C #


Szukam eleganckiego rozwiązania do realizacji odpowiednika C # za pomocą oświadczenia w C ++. Idealnie wypadkowa składnia powinna być łatwa w użyciu i czytaniu.

C # Szczegółowe informacje dotyczące wyciągu znajdują się tutaj - http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

Nie jestem pewien, czy rozwiązaniem byłoby użycie wskaźników funkcyjnych z destruktorami na klasach, jakąś formę sprytnego programowania szablonów, czy nawet programowania szablonów meta. Zasadniczo nie wiem od czego zacząć ...


11
2018-02-03 17:55


pochodzenie


Powiedziano mi, że RAII to omawia. - Anthony Pegram
Jak powiedział Anthony, użycie RAII automatycznie zrobi to za ciebie, a imho, to czyni kod znacznie czystszym niż wzorzec użycia. - Mranz
Z mojego punktu widzenia using słowo kluczowe jest po prostu miernym lekarstwem na brak RAI w pierwszej kolejności. Tak więc nie będziesz starał się naśladować tego. - Andre
@Andre Jest trochę trudniejsze. Przypuszczam, że kompilator C # mógłby traktować zakresowy IDisposable podobny do RAII, ale nie jestem pewien, skąd wiedział, że można bezpiecznie usunąć obiekt. Może sprawdzić liczbę odliczeń, gdy obiekt opuszcza zasięg i natychmiast wywołać komendę, jeśli 0? - Mranz
@DavidHeffernan Mówię o tym, że nie muszę używać zakresu zastosowania. - Mranz


Odpowiedzi:


Nie musisz implementować tego w C ++, ponieważ standardowy wzorzec RAII już robi to, czego potrzebujesz.

{
    ofstream myfile;
    myfile.open("hello.txt");
    myfile << "Hello\n";
}

Po zakończeniu zakresu bloku myfile jest zniszczony, co zamyka plik i zwalnia wszystkie zasoby powiązane z obiektem.

Powód using oświadczenie istnieje w C # jest dostarczenie trochę cukru syntaktycznego wokół try / finally i IDisposable. Po prostu nie jest potrzebny w C ++, ponieważ oba języki różnią się, a problem jest rozwiązywany inaczej w każdym języku.


25
2018-02-03 18:01



To jest o wiele lepsze niż C # usingi działa również z obiektami .NET w C ++ / CLI. Składnia C ++ jest o wiele lepsza, ponieważ mimo to musisz pamiętać o użyciu składni semantyki wartości: (1) Możesz jej użyć dla każdego typu, bez względu na to, czy implementuje IDisposablelub nie, lub dla interfejsów, różne obiekty mogą lub nie mogą, i (2) Działa dla członków klasy. - Ben Voigt
Myślę, że nie jest to sprawa lepsza czy gorsza, to kwestia tego, jakie narzędzia masz do czynienia z problemem w twoim środowisku. C ++ używa sterty jako zarządzania pamięcią, a także stosu, ale nie ma zbierania śmieci, więc na tym polega różnica, opóźnione zarządzanie pamięcią GC, które ma swoje zalety, więc co powinienem zrobić, aby pracować w tym kontekście? nie jesteśmy tutaj różnymi drużynami sportowymi, jesteśmy deweloperami zajmującymi się różnymi technologiami ... - Eugenio Miró
Nie rozumiem, jak to jest akceptowaną odpowiedzią, a przez tak wiele głosów up-voting, ponieważ RAII jest po prostu szefem projektu. Czy nie przygotowuje się do tego, że nie powie, że RAII zajmuje się wszystkim, przez cały czas? Im lepsza odpowiedź, a bardziej analogiczna do C # using oświadczenie wydaje się być Inteligentny wskaźnik użycie, dokładniej, std :: unique_ptr jak wspomniano w innej odpowiedzi tutaj. Inteligentny wskaźnik implementuje opakowanie RAII po stronie wywołania alokacji, więc jest to analogiczne do using. - u8it


Przyjrzałbym się używaniu std :: auto_ptr <> do obsługi czyszczenia wszystkich instancji przydzielonych i przypisanych do wskaźnika w określonym zakresie - w przeciwnym razie wszelkie zmienne zadeklarowane w określonym zakresie zostaną po prostu zniszczone przy wychodzeniu z tego zakresu.

{
    SomeClass A;
    A.doSomething();
} // The destructor for A gets called after exiting this scope here

{
    SomeClass* pA = new SomeClass();
    std::auto_ptr<SomeClass> pAutoA(pA);
    pAutoA->doSomething();
} // The destructor for A also gets called here, but only because we
  // declared a std::auto_ptr<> and assigned A to it within the scope.

Widzieć http://en.wikipedia.org/wiki/Auto_ptr dla trochę więcej informacji na temat std :: auto_ptr <>


3
2018-02-03 18:07



std::auto_ptr jest przestarzałe, użyj std::unique_ptr zamiast - Praetorian
Dobrze wiedzieć, dzięki. Przez większość dni zwykle trzymam się bibliotek Boost ... - hatboyzero
Są inne Inteligentne wskaźniki, oprócz auto_ptr i unique_ptr. - u8it


Bardziej szczegółowy wzór RAII, który przypomina instrukcję użycia C #, można uzyskać za pomocą prostego makra.

#define Using(what, body) { what; body; }

Using(int a=9,
{
    a++;
})

a++; // compile error, a has gone out of scope here

Zauważ, że musimy użyć dużego "Użycie", aby uniknąć kolizji z wbudowaną instrukcją C ++, która oczywiście ma inne znaczenie.


3
2017-09-21 07:28



Podoba mi się to, ponieważ podoba mi się wyraźna natura "używania". Jeśli chodzi o samo makro, to lubię to lepiej: tedclancy.wordpress.com/2015/07/04/raii-helper-macro. - Dina


Chciałbym polecić przeczytanie następujących linków:

  1. C ++ RAII w porównaniu z wzorcem Java Dispose
  2. Wyjątki konstruktora w C ++, C # i Java
  3. Więcej Idiomów w C ++ / Akwizycja zasobów to inicjalizacja
  4. Akwizycja zasobów to inicjalizacja (RAII)

2
2018-02-04 00:04





spójrz na następujące:

#include <iostream>

using namespace std;


class Disposable{
private:
    int disposed=0;
public:
    int notDisposed(){
        return !disposed;
    }

    void doDispose(){
        disposed = true;
        dispose();
    }

    virtual void dispose(){}

};



class Connection : public Disposable {

private:
    Connection *previous=nullptr;
public:
    static Connection *instance;

    Connection(){
        previous=instance;
        instance=this;
    }

    void dispose(){
        delete instance;
        instance = previous;
    }
};

Connection *Connection::instance=nullptr;


#define using(obj) for(Disposable *__tmpPtr=obj;__tmpPtr->notDisposed();__tmpPtr->doDispose())

int Execute(const char* query){
    if(Connection::instance == nullptr){
        cout << "------- No Connection -------" << endl;
        cout << query << endl;
        cout << "------------------------------" << endl;
        cout << endl;

        return -1;//throw some Exception
    }

    cout << "------ Execution Result ------" << endl;
    cout << query << endl;
    cout << "------------------------------" << endl;
    cout << endl;

    return 0;
}

int main(int argc, const char * argv[]) {

    using(new Connection())
    {
        Execute("SELECT King FROM goats");//out of the scope
    }

    Execute("SELECT * FROM goats");//in the scope

}

1
2017-08-29 19:55





    #define USING(...) if(__VA_ARGS__; true)

        USING(int i = 0)
        USING(std::string s = "0")
        {
            Assert::IsTrue(i == 0, L"Invalid result", LINE_INFO());
            Assert::IsTrue(s == "0", L"Invalid result", LINE_INFO());
        }
        //i = 1; // error C2065: 'i': undeclared identifier
        //s = "1"; //error C2065: 's': undeclared identifier

1
2018-03-17 23:43