您能否请C++开发人员详细介绍RAII是什么,为什么重要,以及它是否与其他语言有任何关联?
我做知道一点点.我相信它代表"资源获取是初始化".但是,这个名称并不符合我对RAII的理解(可能不正确):我得到的印象是RAII是一种初始化堆栈中对象的方式,当这些变量超出范围时,析构函数会自动被称为导致资源被清理.
那么为什么不称为"使用堆栈触发清理"(UTSTTC :)?你怎么从那里到"RAII"?
你怎么能在堆栈上创建一些东西来清理堆上的东西呢?此外,是否有不能使用RAII的情况?你有没有发现自己希望收集垃圾?至少一个垃圾收集器,你可以使用一些对象,同时让其他人管理?
谢谢.
我在Web上看到了许多针对Scala的ARM(自动资源管理)示例.虽然大多数看起来很像彼此,但它似乎是一种写作的通道.不过,我确实看到了一个使用延续的非常酷的例子.
无论如何,很多代码都有这种或那种类型的缺陷,所以我认为在Stack Overflow上有一个引用是个好主意,我们可以在这里投票给出最正确和最合适的版本.
Locks AutoCloseable?也就是说,而不是:
Lock someLock = new ReentrantLock();
someLock.lock();
try
{
// ...
}
finally
{
someLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)
我能说......么:
try (Lock someLock = new ReentrantLock())
{
someLock.lock();
// ...
}
Run Code Online (Sandbox Code Playgroud)
在Java 7中?
5 规则指出,如果一个类有一个用户声明的析构函数、复制构造函数、复制赋值构造函数、移动构造函数或移动赋值构造函数,那么它必须有其他 4 个。
但今天我突然明白了:你什么时候需要用户定义的析构函数、复制构造函数、复制赋值构造函数、移动构造函数或移动赋值构造函数?
在我的理解中,隐式构造函数/析构函数适用于聚合数据结构。但是,管理资源的类需要用户定义的构造函数/析构函数。
但是,不能将所有资源管理类都使用智能指针转换为聚合数据结构吗?
例子:
// RAII Class which allocates memory on the heap.
class ResourceManager {
Resource* resource;
ResourceManager() {resource = new Resource;}
// In this class you need all the destructors/ copy ctor/ move ctor etc...
// I haven't written them as they are trivial to implement
};
Run Code Online (Sandbox Code Playgroud)
对比
class ResourceManager {
std::unique_ptr<Resource> resource;
};
Run Code Online (Sandbox Code Playgroud)
现在示例 2 的行为与示例 1 完全相同,但所有隐式构造函数都可以工作。
当然,你不能 copy ResourceManager,但如果你想要不同的行为,你可以使用不同的智能指针。
关键是当智能指针已经有那些隐式构造函数可以工作时,你不需要用户定义的构造函数。
我认为拥有用户定义的构造函数的唯一原因是:
你不能在一些低级代码中使用智能指针(我非常怀疑这种情况)。
您正在自己实现智能指针。
但是,在普通代码中,我看不出有任何理由使用用户定义的构造函数。
我在这里错过了什么吗?
考虑一下代码:
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.createStatement(myQueryString);
rs = ps.executeQuery();
// process the results...
} catch (java.sql.SQLException e) {
log.error("an error!", e);
throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
ps.close();
rs.close();
}
Run Code Online (Sandbox Code Playgroud)
上面没有编译,因为都PreparedStatement.close()和ResultSet.close()抛出java.sql.SQLException.那么我要在finally子句中添加一个try/catch块吗?或者将close语句移动到try子句中?或者只是不打扰打电话?
像SDL等等许多库在他们的教程中都有方法调用,在退出程序之前就可以释放资源,但据我所知,大多数操作系统在退出时从进程中释放所有内存,为什么我需要费心去免费如果应用程序要退出呢?
假设我有一个指向动态分配的10个元素数组的指针:
T* p = new T[10];
Run Code Online (Sandbox Code Playgroud)
后来,我想发布那个数组:
delete[] p;
Run Code Online (Sandbox Code Playgroud)
如果其中一个T析构函数抛出异常会发生什么?其他元素是否仍然被破坏?记忆会被释放吗?是否会传播异常,还是会终止程序执行?
同样地,当一个std::vector<T>被破坏而其中一个T析构者抛出时会发生什么?
我正在考虑开发一款适用于Google App Engine的应用,不应该获得过多的流量.我真的不愿意超过免费配额.但是,通过重载应用程序并超过配额,似乎很容易导致拒绝服务攻击.有没有什么方法可以防止或更难超过免费配额?我知道,例如,我可以限制来自IP的请求数量(使其难以超过CPU配额),但有没有办法让它更难超过请求或带宽配额?
C#有using与IDisposable接口.Java的7+有相同的功能try和AutoCloseable接口.Scala允许您为此问题选择自己的实现.
scala-arm似乎是受欢迎的选择,并由Typesafe员工之一维护.但是,这种简单的行为似乎非常复杂.为了澄清,使用说明很简单,但了解所有代码在内部工作的方式相当复杂.
我刚刚编写了以下超级简单的ARM解决方案:
object SimpleARM {
def apply[T, Q](c: T {def close(): Unit})(f: (T) => Q): Q = {
try {
f(c)
} finally {
c.close()
}
}
}
Run Code Online (Sandbox Code Playgroud)