【问题标题】:What is the Managed C++ equivalent to the C# using statement什么是托管 C++ 等效于 C# using 语句
【发布时间】:2010-09-25 05:37:33
【问题描述】:

如何在托管 C++ 中编写以下 C# 代码

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

澄清: 对于托管对象。

【问题讨论】:

    标签: .net managed-c++ using-statement


    【解决方案1】:

    假设您的意思是 C++/CLI(不是旧的托管 C++),以下是您的选择:

    (1) 使用自动/基于堆栈的对象模拟 using-Block:

    {
      SqlConnection conn(connectionString);
    }
    

    这将在下一个封闭块结束时调用“conn”对象的析构函数。这是封闭函数,还是您手动添加以限制范围的块都没有关系。

    (2) 显式调用“Dispose”,即销毁对象:

    SqlConnection^ conn = nullptr;
    try
    {
      conn = gcnew SqlConnection(conntectionString);
    
    }
    finally
    {
      if (conn != nullptr)
        delete conn;
    }
    

    第一个将是“使用”的直接替代。第二个是一个选项,通常您不需要这样做,除非您有选择地将引用传递给其他地方。

    【讨论】:

    • 第一个语法(使用大括号限制范围)是否保证调用 Dispose,即使您通过抛出异常离开范围?我不认为是这样,但我当然可能是错的。
    • 是的,这是有保证的。确实,这就是这里的想法。堆栈分配对象的析构函数在封闭范围结束时被调用(定期或因异常过早) - 实际上这与托管与否无关。在本机代码中也是如此。
    • @Christian.K,您确定“除非您选择将引用传递给其他地方”吗?我认为即使在这种情况下,示例 (1) 也可以。
    • 需要注意的一点是,当 var 超出范围时,它会为 GC排队,但实际的 GC 可能会“稍后”发生。因此,如果在失去作用域之前进行清理很重要,那么您应该明确地执行此操作,而不是等待析构函数/终结器。我最近有一个例子,我正在写入文件流而不是显式调用stream.Close()。我发现流直到“稍后”(即 GC 运行时)才完全刷新,这导致了问题。解决方案是在流超出范围之前添加对 stream.Close() 的显式调用。
    • @dlchambers 我在这里没有实际经验,但是在 C++/CLI 中使用 AFAIK destructors are deterministic。 IE。当调用析构函数时,实际上是Dispose 被调用。因此,如果您有一个“正确”实现 IDisposable 的类型,您应该没问题。 IE。与 Dispose 无关的实际 GC 时间无关紧要,因为实际清理发生(确定性)在您期望的代码中的点(“var 超出范围”)。跨度>
    【解决方案2】:

    在托管 C++ 中,只需使用堆栈语义即可。

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

    当 con 超出范围时,会调用“析构函数”,即 Dispose()。

    【讨论】:

      【解决方案3】:

      你可以用 auto_ptr 风格做一些类似的

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

      以下内容:

      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)
      

      供参考:

      public ref class Foo
      {
      public:
          Foo() : x(0) {}
          ~Foo()
          {
          }
          int x;
      };
      

      【讨论】:

        【解决方案4】:
        #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
        
        }
        

        【讨论】:

          【解决方案5】:

          如果您担心限制变量的生命周期而不是自动处置,您可以随时将其放入自己的范围:

          void Foo()
          {
              {
                  SqlConnection con = new SqlConnection("connectionStringGoesHere");
                  // do stuff
                  // delete it before end of scope of course!
              }
          }
          

          【讨论】:

          • 这既不会在作用域的末尾调用析构函数,也不会调用“Dispose()”。从这个意义上说,它与 C# 中的效果相同。
          • 是的,你是对的。它不会。我认为这将在“做事”部分完成。我要指出的是 con 不能在新范围之外访问。
          猜你喜欢
          • 2011-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-20
          • 1970-01-01
          相关资源
          最近更新 更多