How do I design a function with a strong exception guarantee? - c++

I have a function which I would like to have the strong exception guarantee:
class X {
/* Fields and stuff */
void some_function() {
vector1.push_back(/*...*/); // May Throw
vector2.push_back(/*...*/); // May Throw
vector3.push_back(/*...*/); // May Throw
vector4.push_back(/*...*/); // May Throw
}
};
The only way I can think of making this having the strong exception guarantee is the following:
class X {
/* Fields and stuff */
void some_function() {
try { vector1.push_back(/*...*/);};
catch (Vector1PushBackException) {
throw Vector1PushBackException;
}
try { vector2.push_back(/*...*/);};
catch (Vector2PushBackException) {
vector1.pop_back();
throw Vector2PushBackException;
}
try { vector3.push_back(/*...*/);};
catch (Vector3PushBackException) {
vector1.pop_back();
vector2.pop_back();
throw Vector3PushBackException;
}
try { vector4.push_back(/*...*/);};
catch (Vector4PushBackException) {
vector1.pop_back();
vector2.pop_back();
vector3.pop_back();
throw Vector4PushBackException;
}
}
};
However, this is really ugly and error-prone!! Is there a better solution than the one I put above? I can hear someone telling me that I need to use RAII, but I can't figure it out how, since the pop_back operations must not be done when the function returns normally.
I would also like any solution to be zero - overhead on the happy path; I really need the happy path to be as fast as possible.

The solution is to use scope guards.
See this answer for an example implementation of them; I'm not going to repeat it here. With scope guards, your code will look like this:
vector1.push_back(/*...*/);
FINALLY_ON_THROW( vector1.pop_back(); )
vector2.push_back(/*...*/);
FINALLY_ON_THROW( vector2.pop_back(); )
vector3.push_back(/*...*/);
FINALLY_ON_THROW( vector3.pop_back(); )
vector4.push_back(/*...*/);
FINALLY_ON_THROW( vector4.pop_back(); )
Here, FINALLY_ON_THROW is a macro (see link above). Rather than executing it's parameter immediately, it causes it to be executed when you leave the current scope because of an exception. If you instead leave the scope the normal way, the parameter is ignored. If you leave the scope before control reaches the guard in the first place, it's also ignored.
Note that the last guard is superfluous if nothing after it (in the same scope) can throw.

A problem with simply popping back is that it won't necessarily restore the vector to the original state. If adding the element caused any of the vectors to reallocate, then iterators / references to the elements would be invalidated and that invalidation cannot be rolled back making strong exception guarantee impossible.
A safe and simple and general solution is to make the modifications on a copy. Copying of course has an extra cost though.
void some_function() {
auto copy = *this;
copy.vector1.push_back(/*...*/); // May Throw
copy.vector2.push_back(/*...*/); // May Throw
copy.vector3.push_back(/*...*/); // May Throw
copy.vector4.push_back(/*...*/); // May Throw
*this = std::move(copy);
}
HolyBlackCat's scope guard suggestion is an elegant solution in cases where rollback is possible such as if you used another container that doesn't invalidate iterators / references, or if you simply don't care about the invalidation or if you have a class invariant that prevents the function from being called when the capacity is full.
You could feasibly, and at marginal extra cost, first check whether all vectors have extra capacity and choose between copying and rollback based on the check. This allows the caller to not pay the cost of copying if they reserve sufficient capacity beforehand. That does stray further from elegance however.

You can do it in many ways... For example like this:
#include <vector>
#include <type_traits>
#include <exception>
template<class F>
struct on_fail
{
F f_;
int count_{ std::uncaught_exceptions() };
~on_fail()
{
// C++20 is here and still no easy way to tell "unwinding" and "leaving scope" apart
if (std::uncaught_exceptions() > count_) f_();
}
};
template<class F> on_fail(F) -> on_fail<F>;
auto emplace_back_x(auto& v, auto&& x)
{
v.emplace_back(std::forward<decltype(x)>(x));
return on_fail{[&v]{ v.pop_back(); }};
}
int bar();
template<class F>
struct inplacer
{
F f_;
operator std::invoke_result_t<F&>() { return f_(); }
};
template<class F> inplacer(F) -> inplacer<F>;
void foo()
{
std::vector<int> v1, v2, v3;
auto rollback1 = emplace_back_x(v1, 1);
auto rollback2 = emplace_back_x(v2, inplacer{ bar });
auto rollback3 = emplace_back_x(v3, inplacer{ []{ return bar() + 1; } });
}
Note that your example is not correct: if push_back() fails with std::bad_alloc (or any other exception) -- you fail to perform undo step.
Also, perhaps in your case it make sense to use basic guarantee? In practice you can often deal with it on a higher level -- e.g. disconnect and discard entire accumulated state, leaving client to reconnect and repeat attempt.

How about this?
class X {
/* Fields and stuff */
void some_function() {
vector1.push_back(/*...*/); // May Throw
try {
vector2.push_back(/*...*/); // May Throw
try {
vector3.push_back(/*...*/); // May Throw
try {
vector4.push_back(/*...*/); // May Throw
} catch(...) {
vector3.pop_back();
throw;
}
} catch(...) {
vector2.pop_back();
throw;
}
} catch(...) {
vector1.pop_back();
throw;
}
}
};
But... do you really need 4 different vectors?
class X {
/* Fields and stuff */
void some_function() {
vector1234.push_back(std::make_tuple(/*...*/, /*...*/, /*...*/, /*...*/)); // May Throw
}
};

Related

When using lambdas for complex initialization of variables, how can I handle outside of the lambda exceptions that are thrown from inside?

I am using lambdas to initialize some const variables as described in the core c++ guidelines here. In short, the idiom looks like this
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
The problem arises when the initialization can throw an exception that can only be handled outside of the lambda, eg because it must cause the function to return early. I want to be able to do something that looks like this
try {
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
}
catch { /* doesn't matter what */ } {
// Somehow handle it
// then return or throw
}
// use a
except that I want the object to be usable after the try-catch block when an exception is not thrown.
I could refactor the function so that all code that depends on successful initialization of the object is inside the try block but this scales horribly with multiple objects to initialize.
try {
const auto a = ...;
try {
const auto b = ...;
try...
catch...
}
catch {...} {
...;
}
catch {...} {
...;
}
On the other hand, moving the try-catch block inside the lambda restricts what I can do to handle it. eg it does not allow me to instantly return, break or continue as far as I can tell. It almost feels like the logical solution would be to interleave the assignment with the try block (eg const auto a = try [&]()...) but it does not seem to be supported by the anguage. Am I correct in that this is not supported and if so is there another known idiom that would result in the behavior I need?
Note: I am asking for situations where it is important for the variable to be const or where default construction followed by assignment is impossible so the obvious solution of default constructing outside the try-block and assigning the value inside it is not viable.
It is honestly no different from simple initialization which also may throw. Try not to micro manage your exceptions. Their power is in allowing you to code freely without worrying about errors every single statement. Put all of the code that does a complete job (or operation) in your try{}catch(){}. An exception should abort the whole procedure, not just a single initialization.
try
{
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
const auto b = "something else that may throw"s;
const auto c = a_throwing_function();
// Now do stuff with a, b and c safe in the knowledge that
// they are properly constructed and valid
// ... etc ...
}
catch(std::exception const& e)
{
// abort the entire operation
}

Recommended way to initialize a const variable with an expression which might throw

You probably know situations like this where you just want to assign to a (const) variable with an expression which might fail (throw) (e.g.container.at()) which forces you to write boiler plate code:
void foo(const string &key) {
auto it = data_store.find(key);
if (it == data_store.end()) {
return;
}
const auto & element = it->second;
...
go on with `element`...
...
}
In Python you could write code like this:
def foo(name):
try:
element = data_store[key]
except KeyError:
return
..
go on with `element`
..
.. with is less noisy because you don't introduce that useless extra it just for checking existence.
If C++'s try would not introduce a variable scope you could just use at():
void foo(const string &key) {
try {
const auto & element = data_store.at(key);
} catch (const out_of_range &) {
return;
}
...
go on with `element`...
...
}
What's the way to go here if you don't want to abandon constness and keep your code clean?
If lambdas only could have a try/catch body you could write
void foo(const string &key) {
const auto & element = [&] () -> T try {
return data_store.at(key);
} catch () {
return;
} ();
...
go on with `element`...
...
}
Some answers to similar questions suggest try/catch blocks around all the code:
void foo(const string &key) {
try {
const auto & element = data_store.at(key);
...
go on with `element`...
...
} catch (const out_of_range &) {
return;
} catch (some other exception) {
...
} catch (some other exception) {
...
}
}
But I don't like this because of three reasons:
there's no visual correlation between at() and it's catch block
there might be code that also need you to handle out_of_range
you have to write nested code
Which (nice, short and clean) alternatives do you know?
There are three good options on this thread, there's not really any other option.
Those cases assume we are initializing an object; for initializing a reference as you are, apply the techniques to std::reference_wrapper, or a pointer.
BTW I would not discount your first code sample so quickly. It's simpler than all the other options, and it is a common recommendation in C++ to only use exceptions for exceptional conditions -- things you do not expect to be a normal part of the function's contract. It's not idiomatic to use them as a shortcut.
In other words, if the function design is to do nothing if the lookup fails, then throw-catching is an unnecessary complication to the function. You've just written an even uglier version of C-style error handling.
The whole point of the at() accessor is that your function can be kept simple by not catching -- the exception can be left to propagate up to a more general error handler.

Prevent or detect "this" from being deleted during use

One error that I often see is a container being cleared whilst iterating through it. I have attempted to put together a small example program demonstrating this happening. One thing to note is that this can often happen many function calls deep so is quite hard to detect.
Note: This example deliberately shows some poorly designed code. I am trying to find a solution to detect the errors caused by writing code such as this without having to meticulously examine an entire codebase (~500 C++ units)
#include <iostream>
#include <string>
#include <vector>
class Bomb;
std::vector<Bomb> bombs;
class Bomb
{
std::string name;
public:
Bomb(std::string name)
{
this->name = name;
}
void touch()
{
if(rand() % 100 > 30)
{
/* Simulate everything being exploded! */
bombs.clear();
/* An error: "this" is no longer valid */
std::cout << "Crickey! The bomb was set off by " << name << std::endl;
}
}
};
int main()
{
bombs.push_back(Bomb("Freddy"));
bombs.push_back(Bomb("Charlie"));
bombs.push_back(Bomb("Teddy"));
bombs.push_back(Bomb("Trudy"));
for(size_t i = 0; i < bombs.size(); i++)
{
bombs.at(i).touch();
}
return 0;
}
Can anyone suggest a way of guaranteeing this cannot happen?
The only way I can currently detect this kind of thing is replacing the global new and delete with mmap / mprotect and detecting use after free memory accesses. This and Valgrind however sometimes fail to pick it up if the vector does not need to reallocate (i.e only some elements removed or the new size is not yet the reserve size). Ideally I don't want to have to clone much of the STL to make a version of std::vector that always reallocates every insertion/deletion during debug / testing.
One way that almost works is if the std::vector instead contains std::weak_ptr, then the usage of .lock() to create a temporary reference prevents its deletion whilst execution is within the classes method. However this cannot work with std::shared_ptr because you do not need lock() and same with plain objects. Creating a container of weak pointers just for this would be wasteful.
Can anyone else think of a way to protect ourselves from this.
Easiest way is to run your unit tests with Clang MemorySanitizer linked in.
Let some continuous-integration Linux box to do it automatically on each push
into repo.
MemorySanitizer has "Use-after-destruction detection" (flag -fsanitize-memory-use-after-dtor + environment variable MSAN_OPTIONS=poison_in_dtor=1) and so it will blow the test up that executes the code and that turns your continuous-integration red.
If you have neither unit tests nor continuous integration in place then you can also just manually debug your code with MemorySanitizer but that is hard way compared with the easiest. So better start to use continuous integration and write unit tests.
Note that there may be legitimate reasons of memory reads and writes after destructor has been ran but memory hasn't yet been freed. For example std::variant<std::string,double>. It lets us to assign it std::string then double and so its implementation might destroy the string and reuse same storage for double. Filtering such cases out is unfortunately manual work at the moment, but tools evolve.
In your particular example the misery boils down to no less than two design flaws:
Your vector is a global variable. Limit the scope of all of your objects as much as possible and issues like this are less likely to occur.
Having the single responsibility principle in mind, I can hardly imagine how one could come up with a class that needs to have some method that either directly or indirectly (maybe through 100 layers of call stack) deletes objects that could happen to be this.
I am aware that your example is artificial and intentionally bad, so please don't get me wrong here: I'm sure that in your actual case it is not so obvious how sticking to some basic design rules can prevent you from doing this. But as I said, I strongly believe that good design will reduce the likelyhood of such bugs coming up. And in fact, I cannot remember that I was ever facing such an issue, but maybe I am just not experienced enough :)
However, if this really keeps being an issue despite sticking with some design rules, then I have this idea how to detect it:
Create a member int recursionDepth in your class and initialize it with 0
At the beginning of each non-private method increment it.
Use RAII to make sure that at the end of each method it is decremented again
In the destructor check it to be 0, otherwise it means that the destructor is directly or indirectly called by some method of this.
You may want to #ifdef all of this and enable it only in debug build. This would essentially make it a debug assertion, some people like them :)
Note, that this does not work in a multi threaded environment.
In the end I went with a custom iterator that if the owner std::vector resizes whilst the iterator is still in scope, it will log an error or abort (giving me a stacktrace of the program). This example is a bit convoluted but I have tried to simplify it as much as possible and removed unused functionality from the iterator.
This system has flagged up about 50 errors of this nature. Some may be repeats. However Valgrind and ElecricFence at this point came up clean which is disappointing (In total they flagged up around 10 which I have already fixed since the start of the code cleanup).
In this example I use clear() which Valgrind does flag as an error. However in the actual codebase it is random access erases (i.e vec.erase(vec.begin() + 9)) which I need to check and Valgrind unfortunately misses quite a few.
main.cpp
#include "sstd_vector.h"
#include <iostream>
#include <string>
#include <memory>
class Bomb;
sstd::vector<std::shared_ptr<Bomb> > bombs;
class Bomb
{
std::string name;
public:
Bomb(std::string name)
{
this->name = name;
}
void touch()
{
if(rand() % 100 > 30)
{
/* Simulate everything being exploded! */
bombs.clear(); // Causes an ABORT
std::cout << "Crickey! The bomb was set off by " << name << std::endl;
}
}
};
int main()
{
bombs.push_back(std::make_shared<Bomb>("Freddy"));
bombs.push_back(std::make_shared<Bomb>("Charlie"));
bombs.push_back(std::make_shared<Bomb>("Teddy"));
bombs.push_back(std::make_shared<Bomb>("Trudy"));
/* The key part is the lifetime of the iterator. If the vector
* changes during the lifetime of the iterator, even if it did
* not reallocate, an error will be logged */
for(sstd::vector<std::shared_ptr<Bomb> >::iterator it = bombs.begin(); it != bombs.end(); it++)
{
it->get()->touch();
}
return 0;
}
sstd_vector.h
#include <vector>
#include <stdlib.h>
namespace sstd
{
template <typename T>
class vector
{
std::vector<T> data;
size_t refs;
void check_valid()
{
if(refs > 0)
{
/* Report an error or abort */
abort();
}
}
public:
vector() : refs(0) { }
~vector()
{
check_valid();
}
vector& operator=(vector const& other)
{
check_valid();
data = other.data;
return *this;
}
void push_back(T val)
{
check_valid();
data.push_back(val);
}
void clear()
{
check_valid();
data.clear();
}
class iterator
{
friend class vector;
typename std::vector<T>::iterator it;
vector<T>* parent;
iterator() { }
iterator& operator=(iterator const&) { abort(); }
public:
iterator(iterator const& other)
{
it = other.it;
parent = other.parent;
parent->refs++;
}
~iterator()
{
parent->refs--;
}
bool operator !=(iterator const& other)
{
if(it != other.it) return true;
if(parent != other.parent) return true;
return false;
}
iterator operator ++(int val)
{
iterator rtn = *this;
it ++;
return rtn;
}
T* operator ->()
{
return &(*it);
}
T& operator *()
{
return *it;
}
};
iterator begin()
{
iterator rtn;
rtn.it = data.begin();
rtn.parent = this;
refs++;
return rtn;
}
iterator end()
{
iterator rtn;
rtn.it = data.end();
rtn.parent = this;
refs++;
return rtn;
}
};
}
The disadvantages of this system is that I must use an iterator rather than .at(idx) or [idx]. I personally don't mind this one so much. I can still use .begin() + idx if random access is needed.
It is a little bit slower (nothing compared to Valgrind though). When I am done, I can do a search / replace of sstd::vector with std::vector and there should be no performance drop.

How do I run a cleanup code on the function exit?

C++ classes provide RAII idiom. Therefore you don't have to care about exceptions:
void function()
{
// The memory will be freed automatically on function exit
std::vector<int> vector(1000);
// Do some work
}
But if you have (for some reasons) to use some pure C API, you have either to create C++ wrappers around it or to use try/catch blocks
void function()
{
int *arr = (int*)malloc(1000*sizeof(int));
if (!arr) { throw "cannot malloc"; }
try
{
// Do some work
}
catch (...)
{
free(arr); // Free memory in case of exception
throw; // Rethrow the exception
}
// Free memory in case of success
free(arr);
}
Even if you use C++ classes with RAII idiom, sometimes you have to write a code with strong exception-safety guaranty:
void function(std::vector<const char*> &vector)
{
vector.push_back("hello");
try
{
// Do some work
vector.push_back("world");
try
{
// Do other work
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("world")
throw; // Rethrow the exception
}
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("hello");
throw; // Rethrow the exception
}
}
But these constructions are quite bulky.
Is there any way to force to run some cleanup code at function exit? Something similar to atexit, but in a function scope...
Is there any way to run some rollback code in case of exception without using nested try/catch blocks?
I would like to have some operators or functions that would work like this:
void function(std::vector<const char*> &vector)
{
int *arr = malloc(1000*sizeof(int));
onexit { free(arr); }
vector.push_back("hello");
onexception { vector.pop_back(); }
// Do some work
vector.push_back("world");
onexception { vector.pop_back(); }
// Do other work
}
If it is possible to create such functions, are there any reasons to avoid using them? Are there such constructs in other programming languages?
I have created macros that implement this functionality. They generate a local variable that runs a cleanup code in the destructor using C++11 lambda functions. The std::uncaught_exception function is used to check if there is any exception currently thrown. Creating the variable itself shouldn't throw any exceptions because a lambda with all variables captured by reference is used to create the variable (such lambdas do not throw exceptions in copy/move constructors).
#include <exception>
// An object of the class below will run an arbitrary code in its destructor
template <bool always, typename TCallable>
class OnBlockExit
{
public:
TCallable m_on_exit_handler;
~OnBlockExit()
{
if (always || std::uncaught_exception())
{ m_on_exit_handler(); }
}
};
// It is not possible to instantiate an object of the 'OnBlockExit' class
// without using the function below: https://stackoverflow.com/a/32280985/5447906.
// Creating of an object of the 'OnBlockExit' class shouldn't throw any exception,
// if lambda with all variables captured by reference is used as the parameter.
template <bool always, typename TCallable>
OnBlockExit<always, TCallable> MakeOnBlockExit(TCallable &&on_exit_handler)
{
return { std::forward<TCallable>(on_exit_handler) };
}
// COMBINE is needed for generating an unique variable
// (the name of the variable contains the line number:
// https://stackoverflow.com/a/10379844/544790)
#define COMBINE1(X,Y) X##Y
#define COMBINE(X,Y) COMBINE1(X,Y)
// ON_BLOCK_EXIT generates a variable with the name
// in the format on_block_exit##__LINE__
#define ON_BLOCK_EXIT(always, code) \
auto COMBINE(on_block_exit,__LINE__) = MakeOnBlockExit<always>([&]()code)
// Below are target macros that execute the 'code' on the function exit.
// ON_FINALLY will allways execute the code on the function exit,
// ON_EXCEPTION will execute it only in the case of exception.
#define ON_EXCEPTION(code) ON_BLOCK_EXIT(false, code)
#define ON_FINALLY(code) ON_BLOCK_EXIT(true , code)
Here is an example how to use these macros:
void function(std::vector<const char*> &vector)
{
int *arr1 = (int*)malloc(800*sizeof(int));
if (!arr1) { throw "cannot malloc arr1"; }
ON_FINALLY({ free(arr1); });
int *arr2 = (int*)malloc(900*sizeof(int));
if (!arr2) { throw "cannot malloc arr2"; }
ON_FINALLY({ free(arr2); });
vector.push_back("good");
ON_EXCEPTION({ vector.pop_back(); });
auto file = fopen("file.txt", "rb");
if (!file) { throw "cannot open file.txt"; }
ON_FINALLY({ fclose(file); });
vector.push_back("bye");
ON_EXCEPTION({ vector.pop_back(); });
int *arr3 = (int*)malloc(1000*sizeof(int));
if (!arr3) { throw "cannot malloc arr3"; }
ON_FINALLY({ free(arr3); });
arr1[1] = 1;
arr2[2] = 2;
arr3[3] = 3;
}
All cleanup code is executed in reverse order (in the order opposite to the order of the ON_FINALLY/ON_EXCEPTION macros appearance in the function). The cleanup code is executed only if control passes beyond the corresponding ON_FINALLY/ON_EXCEPTION macro.
Check the following link to see the output of the demo program execution: http://coliru.stacked-crooked.com/a/d6defaed0949dcc8
C++ has destructors which is what you need. An object that does whatever you need done at scope exit in its destructor that you then create an instance of on the stack in the scope where you need the work done, will get destroyed when the scope is left and then do the work at that time.
ScopeGuard is the right choice for you. It basically calls the function you specify at destructor.
So your code can be:
void your_function() {
scope_guard guard = [&vector]() {
vector.pop_back();
};
// your code
guard.dismiss(); // success
}

Dynamically created scope guards

I've read the article about scope guards (Generic: Change the Way You Write Exception-Safe Code — Forever) in DDJ and I understand their common use.
However, the common use is to instantiate a particular stack guard on the stack for a particular operation, e.g.:
{
FILE* topSecret = fopen("cia.txt");
ON_BLOCK_EXIT(std::fclose, topSecret);
... use topSecret ...
} // topSecret automagically closed
but what if I want to schedule cleanup operations in runtime, e.g. when I have a loop:
{
vector<FILE*> topSecretFiles;
for (int i=0; i<numberOfFiles; ++i)
{
char filename[256];
sprintf(filename, "cia%d.txt", i);
FILE* topSecret = fopen(filename);
topSecretFiles.push_back(topSecret);
ON_BLOCK_EXIT(std::fclose, topSecret); // no good
}
}
Obviously, the above example wouldn't work, since topSecret would be closed along with the for scope. I'd like a scope guard pattern where I can just as easily queue up cleanup operations which I determine to be needed at runtime. Is there something like this available?
I can't push scope guard objects into a standard queue, cause the original object (the one I'm pushing) would be dismissed in the process. How about pushing heap-allocated stack guards and using a queue which deletes its members on dtor? Does anyone have a more clever approach?
It seems you don't appreciate RAII for what it is. These scope guards are nice on occasion for local ("scope") things but you should try to avoid them in favour of what RAII is really supposed to do: encapsulating a resource in an object. The type FILE* is really just not good at that.
Here's an alternative:
void foo() {
typedef std::tr1::shared_ptr<FILE> file_sptr;
vector<file_sptr> bar;
for (...) {
file_sptr fsp ( std::fopen(...), std::fclose );
bar.push_back(fsp);
}
}
Or:
void foo() {
typedef std::tr1::shared_ptr<std::fstream> stream_sptr;
vector<stream_sptr> bar;
for (...) {
file_sptr fsp ( new std::fstream(...) );
bar.push_back(fsp);
}
}
Or in "C++0x" (upcoming C++ standard):
void foo() {
vector<std::fstream> bar;
for (...) {
// streams will become "movable"
bar.push_back( std::fstream(...) );
}
}
Edit: Since I like movable types in C++0x so much and you showed interest in it: Here's how you could use unique_ptr in combination with FILE* without any ref-counting overhead:
struct file_closer {
void operator()(FILE* f) const { if (f) std::fclose(f); }
};
typedef std::unique_ptr<FILE,file_closer> file_handle;
file_handle source() {
file_handle fh ( std::fopen(...) );
return fh;
}
int sink(file_handle fh) {
return std::fgetc( fh.get() );
}
int main() {
return sink( source() );
}
(untested)
Be sure to check out Dave's blog on efficient movable value types
Huh, turns out the DDJ scope guard is "movable", not in the C++0x sense, but in the same sense that an auto_ptr is movable: during the copy ctor, the new guard "dismisses" the old guard (like auto_ptr's copy ctor calls the old one's auto_ptr::release).
So I can simply keep a queue<ScopeGuard> and it'll work:
queue<ScopeGuard> scopeGuards;
// ...
for (...)
{
// the temporary scopeguard is being neutralized when copied into the queue,
// so it won't cause a double call of cleanupFunc
scopeGuards.push_back(MakeScopeGuard(cleanupFunc, arg1));
// ...
}
By the way, thank you for the answer above. It was informative and educational to me in different ways.