【问题标题】:Implementing C++ equivalent of C# using statement使用语句实现与 C# 等效的 C++
【发布时间】:2012-02-26 08:07:42
【问题描述】:

我正在寻找一种优雅的解决方案,用于在 C++ 中实现等效于 C# using 语句。理想情况下,生成的语法应该易于使用和阅读。

C# Using 语句详细信息在这里 - http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

我不确定解决方案是在类上使用带有析构函数的函数指针、某种形式的巧妙模板编程,甚至是元模板编程。基本上我不知道从哪里开始......

【问题讨论】:

  • 我被告知 RAII 涵盖了这个。
  • 正如 Anthony 所说,使用 RAII 会自动为您执行此操作,而且恕我直言,它使代码比 using 模式更简洁。
  • 从我的角度来看,using 关键字只是一开始就没有 RAII 的平庸补救措施。所以,你不要试图效仿它。
  • @Andre 有点难。我想 C# 编译器可以处理类似于 RAII 的作用域 IDisposable,但我不确定它如何知道处置对象是安全的。也许在对象离开范围时检查 ref 计数并在 0 时立即调用 dispose?
  • @DavidHeffernan 我说的是不必使用 using 范围。

标签: c# c++ templates using-statement


【解决方案1】:

您不需要在 C++ 中实现这一点,因为 RAII 的标准模式已经满足您的需求。

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

当块作用域结束时,myfile 被销毁,这会关闭文件并释放与对象关联的所有资源。

using 语句存在于 C# 中的原因是为了在 try/finally 和 IDisposable 周围提供一些语法糖。在 C++ 中根本不需要它,因为两种语言不同,而且每种语言解决问题的方式也不同。

【讨论】:

  • 这远远优于 C# using,它也适用于 C++/CLI 中的 .NET 对象。 C++ 语法要好得多,因为尽管您仍然必须记住使用值语义语法: (1) 您可以将它用于每种类型,无论它是否实现 IDisposable,或者对于接口,不同的对象可能也可以不,并且 (2) 它适用于班级成员。
  • 我认为这不是好坏的问题,而是您必须使用什么工具来处理环境中的问题。 C++使用堆作为内存管理,也使用栈,但是它没有垃圾收集,所以这就是区别,GC延迟内存管理,它有它自己的优势,那么我应该怎么做才能在这种情况下工作呢?我们在这里不是不同的运动队,我们是处理不同技术的开发人员......
  • 我不明白这是如何被接受的答案,并且有如此多的赞成票,因为 RAII 只是一个设计负责人。不说 RAII 一直在照顾一切,这不是让自己陷入困境吗?更好的答案和更类似于 C# 的 using 语句似乎是 Smart Pointer 用法,更具体地说,std::unique_ptr 如另一个答案所提到的这里。智能指针在分配的调用端为您实现了一个 RAII 包装器,类似于using
【解决方案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.

有关 std::auto_ptr 的更多信息,请参阅http://en.wikipedia.org/wiki/Auto_ptr

【讨论】:

  • 很高兴知道,谢谢。大多数时候,我通常还是坚持使用 Boost 库...
  • 除了auto_ptr和unique_ptr还有其他Smart Pointers
【解决方案3】:

类似于 C# 的 using 语句的更详细的 RAII 模式可以通过一个简单的宏来实现。

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

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

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

请注意,我们必须使用大写的“Using”以避免与 C++ 内置的“using”语句发生冲突,后者显然具有不同的含义。

【讨论】:

【解决方案4】:

首先,我们要定义一个 Closeable/Disposable 公共接口:

#include <iostream>

using namespace std;


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

那么我们应该为 using 关键字定义一个宏:

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

和;这是一个示例应用程序:

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
    
}

但是如果你想从内存中自动删除变量,你可以简单地使用大括号{};因此,作用域内的每个变量都将在作用域结束时被删除。 这是一个例子:

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

【讨论】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-18
      • 1970-01-01
      • 2010-09-25
      相关资源
      最近更新 更多