12

我正在尝试在 C++中实现类似于python with 语句的东西。因为我计划主要将它与 Qt-OpenGL 一起使用,所以方法被调用bindrelease(在 python__enter____exit__)。

我想出的代码:

标题:

#include <iostream>
#include <vector>

class With
{
public:
    class A
    {
    public:
        virtual ~A() { }
    };

    template <typename T>
    class B : public A
    {
    public:
        B(T& _t) : t(_t)
        {
            t.bind();
        }

        virtual ~B()
        {
            t.release();
        }

        T& t;
    };

    template <typename... Args>
    With(Args&... args)
    {
        set(args...);
    }

    ~With();

    template <typename T, typename... Args>
    void set(T& t, Args&... args)
    {
        set(t);
        set(args...);
    }

    template <typename T>
    void set(T& t)
    {
        a.push_back(dynamic_cast<A*>(new B<T>(t)));
    }

    std::vector<A*> a;
};

cp:

With::~With()
{
    for (auto it = a.begin(); it != a.end(); ++it)
    {
        delete *it;
    }
}

用法:

class X
{
public:
    void bind() { std::cout << "bind x" << std::endl; }
    void release() { std::cout << "release x" << std::endl; }
};

class Y
{
public:
    void bind() { std::cout << "bind y" << std::endl; }
    void release() { std::cout << "release y" << std::endl; }
};

int main()
{
    X y;
    Y y;

    std::cout << "start" << std::endl;
    {
        With w(x, y);
        std::cout << "with" << std::endl;
    }

    std::cout << "done" << std::endl;

    return 0;
}

问题:

  1. 需要class Aclass B感觉有点笨拙。有更好的选择吗?
  2. &&使用而不是有什么缺点&吗?这将使临时对象的使用成为可能(例如With w(X(), y);
4

3 回答 3

13

with 语句是在 python 中执行 C++ 中已经很正常的事情的一种方式。它被称为 RAII:资源获取是初始化。

在python中,当创建一个类对象时,__init__会调用该方法(但这不是一个严格的保证)。该__del__方法在对象不再使用后的某个时间点由垃圾收集器调用,但它不是确定性的。

在 C++ 中,析构函数在定义明确的点被调用,因此不需要with.

我建议您只使用B 类之类的东西(不需要 A 类或 With)。

template <typename T>
class B {
public:
    B(T& t) : m_t(t){
        m_t.bind();
    }
    ~B() {
        m_t.release();
    }
    T& m_t;
}

像这样使用它:

{
    B<X> bound_x(x);  // x.bind is called
    B<Y> bound_y(y);  // y.bind is called
    // use x and y here
} // bound_x and bound_y is destroyed here 
  // so x.release and y.release is called    
于 2012-07-15T16:59:32.860 回答
2

它随语言一起提供,称为 RAII。

struct X {
    X() { std::cout << "bind\n"; }
    ~X() { std::cout << "release\n"; }
};
int main() {
    X x;
}
于 2012-07-15T17:16:52.683 回答
1

一种可能的解决方案:

template <typename T>
void with(T *t, std::function<void ()> fn) {
    t->bind();
    fn();
    t->unbind();
}

用法:

with(object, []() {
    // object bound
});
于 2018-04-11T13:55:48.887 回答