Implementing C++ equivalent of C# using statement

8.5k Views Asked by At

I am looking for an elegant solution for implementing the equivalent of the C# using statement in C++. Ideally the resultant syntax should be simple to use and read.

C# Using statement details are here - http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

I am not sure whether the solution would be to use function pointers with destructors on classes, some form of clever template programming or even meta template programming. Basically I do not know where to start with this...

7

There are 7 best solutions below

4
On BEST ANSWER

You don't need to implement this in C++ because the standard pattern of RAII already does what you need.

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

When the block scope ends, myfile is destroyed which closes the file and frees any resources associated with the object.

The reason the using statement exists in C# is to provide some syntactic sugar around try/finally and IDisposable. It is simply not needed in C++ because the two languages differ and the problem is solved differently in each language.

0
On

First, we have to define a Closeable/Disposable public interface:

#include <iostream>

using namespace std;


class Disposable{
private:
    int disposed=0;
public:
    int notDisposed(){
        return !disposed;
    }
    
    void doDispose(){
        disposed = true;
        dispose();
    }
    
    virtual void dispose(){}
    
};

Then we should define a macro for the using keyword:

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

and; here is an example application:

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;

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");//in the scope 
    }
    
    Execute("SELECT * FROM goats");//out of the scope
    
}

But if you want to delete variables automatically from memory, you can simply use braces {}; therefore, every variable inside of the scope will be removed at the end of the scope. here is an example:

int main(int argc, const char * argv[]) {
    {
        int i=23;
    } 
    
    // the variable i has been deleted from the momery at here.
} 
2
On

I'd take a look at using std::auto_ptr<> to handle cleanup of any instances allocated and assigned to a pointer within a particular scope -- otherwise, any variables declared within a specific scope will simply be destructed when exiting said scope.

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

See http://en.wikipedia.org/wiki/Auto_ptr for a little more information on std::auto_ptr<>

0
On
1
On

A more verbose RAII pattern that resembles C#'s using statement can be accomplished with a simple macro.

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

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

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

Note we must use a capital "Using" to avoid a collision with C++'s built in "using" statement which obviously has a different meaning.

0
On
    #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
0
On

As an alternative to other answers that emphasizes your RAII object, doesn't require macros and has a very similar syntax to C#:

if(std::ofstream myfile("hello.txt"); true) {
    // code 
};

The object is put apart from the code inside the curly braces, same as in C#:

using (StreamReader reader = File.OpenText("hello.txt")) {
    // code 
}

A separate keyword like in C#, instead of if would be better, of course.

With a macro, similar to C# syntax:

#define Using(what) if(what; true)

Using(std::ofstream myfile("hello.txt")) {
        // code 
};

Requires C++ 17.