24

How would one code the following C# code in Managed C++

void Foo()
{
    using (SqlConnection con = new SqlConnection("connectionStringGoesHere"))
    {
         //do stuff
    }
}

Clarificaton: For managed objects.

mwigdahl
  • 16,268
  • 7
  • 50
  • 64
Adam Tegen
  • 25,378
  • 33
  • 125
  • 153

5 Answers5

35

Assuming you mean C++/CLI (not the old Managed C++), the following are your options:

(1) Mimic a using-Block with using automatic / stackbased objects:

{
  SqlConnection conn(connectionString);
}

This will call the Destructor of the "conn" Object when the next enclosing block ends. Whether this is the enclosing function, or a block you manually add to limit scope doesn't matter.

(2) Explicitly call "Dispose", i.e. destruct the object:

SqlConnection^ conn = nullptr;
try
{
  conn = gcnew SqlConnection(conntectionString);

}
finally
{
  if (conn != nullptr)
    delete conn;
}

The first one would be the direct replacement for "using". The second one is an option, typically you won't need to do unless you optionally pass the reference to somewhere else.

Christian.K
  • 47,778
  • 10
  • 99
  • 143
  • 1
    Is the first syntax (using bare curly-braces to limit scope) guaranteed to call Dispose even if you leave scope by throwing an exception? I did not think that was the case, but of course I could be wrong. – Coderer Dec 04 '08 at 15:08
  • Yes its guaranted. Indeed that is the idea here. Destructors of stack-allocated objects are called when the enclosing scope ends (either regularly or prematurely by an exception) - actually that has nothing to do with managed or not. It is also this way in native code. – Christian.K Dec 05 '08 at 05:40
  • @Christian.K, are you sure about "unless you optionally pass the reference to somewhere else"? I think that example (1) would be fine even in that case. – JoelFan Nov 07 '11 at 13:38
  • @JoelFan Frankly, I can't recall what I originally ment here ;-) Of course you are correct: you could pass the object from (1) to other places as well. I could only assume that I ment that in the second case you can also "pass the option" to delete the object to somewhere else (i.e. let someone else take over the lifetime management of it). – Christian.K Nov 08 '11 at 05:33
  • 4
    One thing to note is that when the var goes out of scope it is *queued* for GC, but the actual GC may occur "later". Thus if it's important for cleanup to occur before you lose scope, you'd want to do that explicitly instead of waiting for the destructor/finalizer. I had an example of this recently where I was writing to a filestream and not explicitly calling stream.Close(). I found that the stream wasn't fully flushed until "some later time" (ie. when the GC ran) and this was causing problems. The solution was to add an explicit call to stream.Close() before stream went out of scope. – dlchambers Nov 17 '11 at 17:31
  • 3
    @dlchambers I have no practical experience here, but AFAIK [destructors are deterministic](http://www.codeproject.com/KB/mcpp/cppclidtors.aspx) in C++/CLI. I.e. when the destructor is called, it is really `Dispose` that is called. So if you have a type that "properly" implements `IDisposable` you should be fine. I.e. time of actual GC, which has nothing to do with `Dispose` as such, doesn't matter, because actual cleanup happens (deterministic) at the point in the code you would expect ("var goes out of scope"). – Christian.K Nov 18 '11 at 06:01
  • Actually, in native C++, the destructor is only guaranteed to be called if the exception is caught - http://stackoverflow.com/q/8311457/986 (though obviously if it's not caught, the application will crash anyway). – Mark Ingram Feb 02 '15 at 12:05
  • I love it. How do I get C# and VB.net to also do this!? – Brain2000 Dec 04 '18 at 19:30
3

To to that in Managed C++ just use stack semantics.

void Foo(){
   SqlConnection con("connectionStringGoesHere");
    //do stuff
}

When con goes out of scope the "Destructor", ie Dispose(), is called.

jyoung
  • 5,071
  • 4
  • 30
  • 47
2

You could do something similar in an auto_ptr style:

void foo()
{
    using( Foo, p, gcnew Foo() )
    {
        p->x = 100;
    }
}

with the following:

template <typename T>
public ref class using_auto_ptr
{
public:
    using_auto_ptr(T ^p) : m_p(p),m_use(1) {}
    ~using_auto_ptr() { delete m_p; }
    T^ operator -> () { return m_p; }
    int m_use;
private:
    T ^ m_p;
};

#define using(CLASS,VAR,ALLOC) \
    for ( using_auto_ptr<CLASS> VAR(ALLOC); VAR.m_use; --VAR.m_use)

For reference:

public ref class Foo
{
public:
    Foo() : x(0) {}
    ~Foo()
    {
    }
    int x;
};
Nick
  • 27,566
  • 12
  • 60
  • 72
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

}
Siamand
  • 1,080
  • 10
  • 19
-3

If you're concerned about limiting the variable's lifetime rather than automatic disposal, you can always just put it into its own scope:

void Foo()
{
    {
        SqlConnection con = new SqlConnection("connectionStringGoesHere");
        // do stuff
        // delete it before end of scope of course!
    }
}
Mike Hall
  • 1,151
  • 2
  • 10
  • 24
  • 1
    This will neither call the destructor at the end of the scope, nor will "Dispose()" be called. It that sense it has the same effect as in C#. – Christian.K Dec 04 '08 at 07:31
  • Yes, you're correct. It won't. I assumed that would be done in the "do stuff" part. All I was pointing out is that con can't be accessed outside of that new scope. – Mike Hall Dec 06 '08 at 22:01