避免调用可能会引发析构函数的函数
Avoid a call to a function that may throw in a destructor
我有一个 ODBC 包装器接口,使我能够在 C++ 中执行 SQL 查询。特别是,我使用
named parameter idiom 为
select 语句,例如:
Table.Select("foo").GroupBy("bar").OrderBy("baz");
要实现这个效果,classTable_t
returns一个代理对象Select_t
:
class Table_t
{
// ...
public:
Select_t Select(std::string const &Stmt)
{ return {*this, Stmt}; }
void Execute(std::string const &Stmt);
};
Select_t
将基本语句与附加子句结合起来,并在析构函数中执行实际语句:
class Select_t
{
private:
Table_t &Table;
std::string SelectStmt,
OrderStmt,
GroupStmt;
public:
Select_t(Table_t &Table_, std::string const &SelectStmt) :
Table(Table_), SelectStmt(SelectStmt_) {}
~Select_t()
{ /* Combine the statements */ Table.Execute(/* Combined statement */); }
Select_t &OrderBy(std::string const &OrderStmt_)
{ OrderStmt = OrderStmt_; return *this; }
Select_t &GroupBy(std::string const &GroupStmt_)
{ GroupStmt = GroupStmt_; return *this; }
};
问题是 Table.Execute(Stmt)
可能会抛出而我不能抛出析构函数。有没有
我可以在保留命名参数习惯用法的同时解决这个问题吗?
到目前为止,我想到的唯一想法是向 Select_t
添加一个 Execute
函数,但我不想这样做:
Table.Select("foo").GroupBy("bar").OrderBy("baz").Execute();
抛出"inside"一个析构函数不是问题;问题是从析构函数中逃逸的异常。您需要捕获 ODBC 异常,并决定如何通过另一个接口传达错误。
实际上,将查询对象及其执行的关注点分开可能是个好主意。
惰性调用非常有用。
Execute
函数可以合理地成为一个免费函数。
例如:
auto myquery = Table.Select("foo").GroupBy("bar").OrderBy("baz");
auto future_result = marshal_to_background_thread(myquery);
//or
auto result = Execute(myquery);
这将有助于重新使用准备好的语句。
例如
auto myquery = Prepare(Table.Select("foo").Where(Equals("name", Param(1))).OrderBy("baz"));
auto result = Execute(myquery, {1, "bob"});
result = Execute(myquery, {1, "alice"});
我有一个 ODBC 包装器接口,使我能够在 C++ 中执行 SQL 查询。特别是,我使用 named parameter idiom 为 select 语句,例如:
Table.Select("foo").GroupBy("bar").OrderBy("baz");
要实现这个效果,classTable_t
returns一个代理对象Select_t
:
class Table_t
{
// ...
public:
Select_t Select(std::string const &Stmt)
{ return {*this, Stmt}; }
void Execute(std::string const &Stmt);
};
Select_t
将基本语句与附加子句结合起来,并在析构函数中执行实际语句:
class Select_t
{
private:
Table_t &Table;
std::string SelectStmt,
OrderStmt,
GroupStmt;
public:
Select_t(Table_t &Table_, std::string const &SelectStmt) :
Table(Table_), SelectStmt(SelectStmt_) {}
~Select_t()
{ /* Combine the statements */ Table.Execute(/* Combined statement */); }
Select_t &OrderBy(std::string const &OrderStmt_)
{ OrderStmt = OrderStmt_; return *this; }
Select_t &GroupBy(std::string const &GroupStmt_)
{ GroupStmt = GroupStmt_; return *this; }
};
问题是 Table.Execute(Stmt)
可能会抛出而我不能抛出析构函数。有没有
我可以在保留命名参数习惯用法的同时解决这个问题吗?
到目前为止,我想到的唯一想法是向 Select_t
添加一个 Execute
函数,但我不想这样做:
Table.Select("foo").GroupBy("bar").OrderBy("baz").Execute();
抛出"inside"一个析构函数不是问题;问题是从析构函数中逃逸的异常。您需要捕获 ODBC 异常,并决定如何通过另一个接口传达错误。
实际上,将查询对象及其执行的关注点分开可能是个好主意。
惰性调用非常有用。
Execute
函数可以合理地成为一个免费函数。
例如:
auto myquery = Table.Select("foo").GroupBy("bar").OrderBy("baz");
auto future_result = marshal_to_background_thread(myquery);
//or
auto result = Execute(myquery);
这将有助于重新使用准备好的语句。
例如
auto myquery = Prepare(Table.Select("foo").Where(Equals("name", Param(1))).OrderBy("baz"));
auto result = Execute(myquery, {1, "bob"});
result = Execute(myquery, {1, "alice"});