在C#中,如果我想确定性地清理非托管资源,我可以使用"using"关键字.但是对于多个依赖对象,这最终会进一步嵌套:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (StreamReader sr = new StreamReader(bs))
{
// use sr, and have everything cleaned up when done.
}
}
}
Run Code Online (Sandbox Code Playgroud)
在C++中,我习惯于使用析构函数来执行此操作:
{
FileStream fs("c:\file.txt", FileMode.Open);
BufferedStream bs(fs);
StreamReader sr(bs);
// use sr, and have everything cleaned up when done.
}
Run Code Online (Sandbox Code Playgroud)
在C#中有更好的方法吗?还是我坚持多层次的嵌套?
在什么情况下垃圾收集比手动内存管理更有效?(这里的手册可能意味着在C中使用malloc和free,或者使用C++推广的更清晰的RAII和智能指针技术)
我喜欢垃圾收集如何通过编写软件来消除一些偶然的复杂性,但我更加高兴RAII和智能指针如何消除这种复杂性,同时还可以处理除内存以外的资源,确定性,提供性能保证和更高效总体.所以我想我可以安全地忽略垃圾收集.但是,我注意到人们一直在说垃圾收集比C++中使用的紧密资源管理更快,例如当有大量额外内存可用时.
那么什么时候垃圾收集完全可以胜过手动内存管理呢?我喜欢RAII和智能指针,但如果速度更快,我很乐意接受垃圾收集作为另一种工具.
在C++中,在析构函数中检测它是否正在由于抛出异常而在堆栈展开期间运行而不是正常退出触发析构函数的范围有什么好方法?我想知道,以便我可以创建一个具有一些清理代码的类,该代码始终在正常退出时运行,但在发生异常时跳过.
我正在阅读Stroustrup的C++(3ed,1997),看看他是如何实现RAII的,在第365页我发现了这个:
class File_ptr{
FILE* p;
public:
File_ptr(const char* n, const char* a){p = fopen(n, a);}
File_ptr(FILE* pp) { p = pp; }
~File_ptr() {fclose(p);}
operator FILE* () {return p;}
};
Run Code Online (Sandbox Code Playgroud)
构造函数和析构函数的实现是显而易见的,并且符合RAII惯用法,但我不明白他为什么使用它operator FILE* () {return p;}.
这将导致以File_ptr下列方式使用:
FILE* p = File_ptr("myfile.txt", "r");
Run Code Online (Sandbox Code Playgroud)
结果是封闭的p,在这种情况下在语义上是不合适的.此外,如果File_ptr要用作RAII,则此运算符允许它像示例中那样被滥用.或者我错过了什么?
资源获取是初始化(RAII)在C++中是常用的管理需要的清理代码某种方式在它们的寿命结束时,从资源的寿命delete荷兰国际集团new编指针释放文件句柄.
如何快速轻松地使用RAII来管理从C风格API获取的资源的生命周期?
在我的情况下,我想使用RAII从C风格的API中自动执行清理函数,当它发布的C风格资源的变量超出范围时.我不需要额外的资源包装,我想在这里最小化使用RAII的代码开销.有没有一种简单的方法可以使用RAII来管理C风格的API资源?
如何将C api封装到RAII C++类中?是相关的,但我不认为这是一个重复 - 这个问题是关于更完整的封装,而这个问题是关于获得RAII的好处的最小代码.
我正在学习C++中的RAII习语,以及如何使用智能指针.
在我的阅读中,我遇到了两件对我来说似乎相互矛盾的事情.
引用自http://www.hackcraft.net/raii/:
...如果已经创建了具有RAII语义的成员对象并且在构造函数完成之前发生了异常,那么它的析构函数将作为堆栈展开的一部分被调用.因此,即使没有使用成员RAII对象完全构造,控制多个资源的对象也可以保护它们的清理.
但引自http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10:
如果构造函数抛出异常,则不会运行该对象的析构函数.如果您的对象已经完成了需要撤消的操作(例如分配一些内存,打开文件或锁定信号量),则必须通过对象内的数据成员记住这些"需要撤消的内容".
然后第二个链接源建议使用智能指针来处理已在构造函数中分配的事物的问题.
那么这些场景中究竟发生了什么?
随着try-with-resourceJava 7的推出,我很惊讶地看到Lock它还没有被改造成一个AutoCloseable.它似乎相当简单,所以我自己添加如下:
class Lock implements AutoCloseable {
private final java.util.concurrent.locks.Lock _lock;
Lock(java.util.concurrent.locks.Lock lock) {
_lock = lock;
_lock.lock();
}
@Override
public void close() {
_lock.unlock();
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于一个AutoCloseableReentrantReadWiteLock类,用法如下:
try (AutoCloseableReentrantReadWiteLock.Lock l = _lock.writeLock()) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
由于这似乎是直接和规范使用自动关闭RAII我认为必须有一个很好的理由这不应该做.有人知道吗?
来自C++背景,我是RAII模式的忠实粉丝.我已经广泛使用它来处理内存管理和锁管理以及其他用例.
使用Java 1.7,我看到我可以使用try-with-resources模式来创建RAII模式.
我使用RAII创建了一个示例应用程序并且它可以工作,但是我看到java中的编译器警告.
样品申请
try(MyResource myVar = new MyResource(..))
{
//I am not using myVar here
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误
warning: [try] auto-closeable resource node is never referenced in body of corresponding try statement
Run Code Online (Sandbox Code Playgroud)
我理解警告,这意味着我应该在try块中使用变量,我不需要一直这样做.
看看这个我假设Java并没有真正支持RAII,我可能误用了仅用于资源管理的功能,而不是C++中的RAII等价物.
几个问题:
for 4我正在考虑将构造函数调用拆分为更简单的构造函数和像这样的实例方法
try(MyResource myVar = new Resource())
{
myvar.Initialize()
....
}
Run Code Online (Sandbox Code Playgroud)
这解决了编译器的问题,但从设计的RAII中获取了本质.
对于许多RAII"守卫"类,被实例化为匿名变量根本没有意义:
{
std::lock_guard<std::mutex>{some_mutex};
// Does not protect the scope!
// The unnamed instance is immediately destroyed.
}
Run Code Online (Sandbox Code Playgroud)
{
scope_guard{[]{ cleanup(); }};
// `cleanup()` is executed immediately!
// The unnamed instance is immediately destroyed.
}
Run Code Online (Sandbox Code Playgroud)
从这篇文章:
C++中的匿名变量具有"表达式范围",这意味着它们在创建它们的表达式的末尾被销毁.
有没有办法阻止用户在没有名字的情况下实例化它们? ("预防"可能过于强烈 - "使其非常困难"也是可以接受的).
我可以想到两种可能的解决方法,但是它们在使用类时引入了语法开销:
在detail命名空间中隐藏类并提供宏.
namespace detail
{
class my_guard { /* ... */ };
};
#define SOME_LIB_MY_GUARD(...) \
detail::my_guard MY_GUARD_UNIQUE_NAME(__LINE__) {__VA_ARGS__}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但是是hackish.
只允许用户通过高阶函数使用警卫.
template <typename TArgTuple, typename TF>
decltype(auto) with_guard(TArgTuple&& guardCtorArgs, TF&& f)
{ …Run Code Online (Sandbox Code Playgroud)我现在开始使用CUDA并且不得不承认我对C API有点失望.我理解选择C的原因,但是语言基于C++而不是,有几个方面会更简单,例如设备内存分配(via cudaMalloc).
我的计划是这样做我自己,用重载operator new与安置new和RAII(两种选择).我想知道到目前为止我是否有任何警告.代码似乎工作,但我仍然想知道潜在的内存泄漏.
RAII代码的用法如下:
CudaArray<float> device_data(SIZE);
// Use `device_data` as if it were a raw pointer.
Run Code Online (Sandbox Code Playgroud)
也许一个类在这种情况下是过度的(特别是因为你仍然必须使用cudaMemcpy,该类只封装RAII)所以另一种方法是放置new:
float* device_data = new (cudaDevice) float[SIZE];
// Use `device_data` …
operator delete [](device_data, cudaDevice);
Run Code Online (Sandbox Code Playgroud)
这里,cudaDevice仅作为触发过载的标签.但是,由于在正常放置中new这将指示放置,我发现语法奇怪地一致,甚至可能更喜欢使用类.
我很欣赏各种批评.是否有人知道是否计划为下一版本的CUDA(正如我所听到的那样,将改进其C++支持,无论它们的含义是什么).
所以,我的问题实际上有三个:
new超载语义正确?它会泄漏内存吗?// Singleton tag for CUDA device memory placement.
struct CudaDevice {
static CudaDevice const& get() { return instance; }
private:
static …Run Code Online (Sandbox Code Playgroud) raii ×10
c++ ×8
exception ×2
java ×2
auto-close ×1
c# ×1
c++-faq ×1
c++11 ×1
c++14 ×1
c++17 ×1
constructor ×1
cuda ×1
destructor ×1
pointers ×1
using ×1