[cfe-dev] Parser Stmt/Expr Owning Pointer
Howard Hinnant
hhinnant at apple.com
Tue Dec 9 12:02:44 PST 2008
On Dec 9, 2008, at 2:39 PM, Sebastian Redl wrote:
> Howard Hinnant wrote:
>> I haven't traced this down exactly, so I'm not sure there's a
>> problem. But in:
>>
>> template <void (Action::*Destroyer)(void*)>
>> class ASTMove {
>> ASTOwner<Destroyer> &Moved;
>>
>> public:
>> explicit ASTMove(ASTOwner<Destroyer> &moved) : Moved(moved) {}
>> ...
>>
>> we store a reference to the ASTOwner. And I also see client code
>> that looks like:
>>
>> ExprOwner Idx(Actions, ParseAssignmentExpression());
>> if (Idx.isInvalid()) {
>> SkipUntil(tok::r_square);
>> return Idx.move();
>> }
>>
>> Are we in danger of returning a reference to the local variable Idx?
>>
> No. The return type is an ExprResult, which is initialized with the
> ASTMove. As long as no one gets the idea that using an ASTMove as a
> return type is a good thing (it *isn't*), there's no problem.
Here's one way you can have the compiler enforce that good rule:
/// RAII owning pointer for StmtTys and ExprTys. Simple move
emulation.
template <void (Action::*Destroyer)(void*)>
class ASTOwner {
Action &Actions;
void *Node;
bool Invalid;
void destroy() {
if (Node)
(Actions.*Destroyer)(Node);
}
// Move emulation
ASTOwner(ASTOwner&); // DO NOT IMPLEMENT
ASTOwner& operator=(ASTOwner&); // DO NOT IMPLEMENT
struct ASTMove
{
Action &Actions;
void *Node;
bool Invalid;
ASTMove(Action &actions, void *p, bool Inv)
: Actions(actions), Node(p), Invalid(Inv) {}
};
public:
operator ASTMove() {return ASTMove(Actions, take(), Invalid);}
ASTOwner(ASTMove r)
: Actions(r.Actions), Node(r.Node), Invalid(r.Invalid) {}
ASTOwner& operator=(ASTMove r) {
reset(r.ptr_);
Invalid = r.Invalid;
// Actions = r.Actions;?
return *this;
}
friend ASTOwner move(ASTOwner& p) {return ASTOwner(ASTMove(p));}
// End move emulation
explicit ASTOwner(Action &actions, bool invalid = false)
: Actions(actions), Node(0), Invalid(invalid) {}
ASTOwner(Action &actions, void *node)
: Actions(actions), Node(node), Invalid(false) {}
void reset(void *node = 0) {
destroy();
Node = node;
Invalid = false;
}
void *take() {
void *Temp = Node;
Node = 0;
return Temp;
}
void *get() const { return Node; }
bool isInvalid() const { return Invalid; }
bool isUsable() const { return !Invalid && Node; }
};
ASTMove is now a private nested class of ASTOwner. No one can even
mention it's existence. And ASTOwner is moveable but not copyable.
You can return an ASTOwner from a function (with move(expr)), and pass
it by value to a sink, as long as the expression is an rvalue or the
result of move(expr) (which is nothing but an rvalue ASTOwner).
Disclaimer: I may have some details particular to ASTOwner in the
above sketch incorrect. The intent is to show how to add move
emulation to C++03 types (it's easier when you don't have to deal with
converting constructors).
-Howard
More information about the cfe-dev
mailing list