2012-02-03 3 views
10

Я ищу элегантное решение для реализации эквивалента оператора C# using в C++. В идеале результирующий синтаксис должен быть прост в использовании и чтении.Реализация C++ эквивалента C# с использованием оператора

C# Использование деталей выписки здесь - http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

Я не уверен, будет ли решение будет использовать указатели на функции с деструкторов на классы, некоторые формы умного программирования шаблона или даже мета-программирования шаблона. В основном я не знаю, с чего начать ...

+13

Я сказал RAII охватывает это. –

+1

Как сказал Энтони, использование RAII автоматически сделает это за вас, а imho - делает код намного чище, чем используемый шаблон. – Mranz

+4

С моей точки зрения ключевое слово 'using' - это просто посредственное средство от того, что у вас вообще нет RAII. Итак, ты не будешь подражать ему. – Andre

ответ

24

Вам не нужно реализовывать это на C++, потому что стандартный шаблон RAII уже делает то, что вам нужно.

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

Когда объем блока заканчивается, myfile разрушается, который закрывает файл и освобождает все ресурсы, связанные с объектом.

Причина, по которой оператор using существует в C#, заключается в предоставлении синтаксического сахара вокруг try/finally и IDisposable. Это просто не нужно в C++, потому что эти два языка различаются, и проблема решается по-разному на каждом языке.

+2

Это намного превосходит C# 'using', а также работает с объектами .NET в C++/CLI. Синтаксис C++ намного лучше, потому что вы все равно должны помнить, что используете синтаксис семантики значения: (1) Вы можете использовать его для каждого типа, независимо от того, реализует ли он «IDisposable» или нет, или для интерфейсов, разные объекты могут или не может, и (2) Он работает для учеников. –

+1

Я думаю, что дело не в лучшем или худшем, это вопрос того, какие инструменты вы должны решать с проблемой в своей среде. C++ использует кучу в качестве управления памятью, а также стек, но у нее нет сборки мусора, так что это разница, управление задержкой памяти GC, у которой есть свои преимущества, и что мне делать, чтобы работать в этом контексте? мы не разные спортивные команды здесь, мы разработчики, занимающиеся различными технологиями ... –

2

Я бы посмотрел на использование std :: auto_ptr <> для обработки очистки любых экземпляров, выделенных и назначенных указателю в определенной области - в противном случае любые переменные, объявленные в определенной области, будут просто разрушены, если выходя из указанного объема.

{ 
    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. 

Смотрите http://en.wikipedia.org/wiki/Auto_ptr для немного больше информации о станд :: auto_ptr <>

+2

'std :: auto_ptr' устарел, используйте' std :: unique_ptr' вместо – Praetorian

+0

Полезно знать, спасибо. В большинстве дней я обычно придерживаюсь библиотек Boost ... – hatboyzero

2

Более подробный шаблон RAII, который напоминает, используя заявление C# 's может быть достигнуто с помощью простого макроса.

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

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

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

Примечание мы должны использовать капитал «Использование», чтобы избежать столкновения с C++ 's встроенный „используя“ заявление, которое, очевидно, имеет другое значение.

+0

Мне это нравится, потому что мне нравится явный характер «использования». Что касается самого макроса, мне это нравится лучше: https://tedclancy.wordpress.com/2015/07/04/raii-helper-macro/. – Dina

0

взгляд на следующее:

#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 

}