这个C++代码异常是否安全?

phi*_*inz 4 c++ exception

我有来自mysql.com的以下代码:

/* Copyright 2008, 2010, Oracle and/or its affiliates. All rights reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

There are special exceptions to the terms and conditions of the GPL
as it is applied to this software. View the full text of the
exception in file EXCEPTIONS-CONNECTOR-C++ in the directory of this
software distribution.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

/* Standard C++ includes */
#include <stdlib.h>
#include <iostream>

/*
  Include directly the different
  headers from cppconn/ and mysql_driver.h + mysql_util.h
  (and mysql_connection.h). This will reduce your build time!
*/
#include "mysql_connection.h"

#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>

using namespace std;

int main(void)
{
cout << endl;
cout << "Running 'SELECT 'Hello World!' AS _message'..." << endl;

try {
  sql::Driver *driver;
  sql::Connection *con;
  sql::Statement *stmt;
  sql::ResultSet *res;

  /* Create a connection */
  driver = get_driver_instance();
  con = driver->connect("tcp://127.0.0.1:3306", "root", "root");
  /* Connect to the MySQL test database */
  con->setSchema("test");

  stmt = con->createStatement();
  res = stmt->executeQuery("SELECT 'Hello World!' AS _message");
  while (res->next()) {
    cout << "\t... MySQL replies: ";
    /* Access column data by alias or column name */
    cout << res->getString("_message") << endl;
    cout << "\t... MySQL says it again: ";
    /* Access column data by numeric offset, 1 is the first column */
    cout << res->getString(1) << endl;
  }
  delete res;
  delete stmt;
  delete con;

} catch (sql::SQLException &e) {
  cout << "# ERR: SQLException in " << __FILE__;
  cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
  cout << "# ERR: " << e.what();
  cout << " (MySQL error code: " << e.getErrorCode();
  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}

cout << endl;

return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

我一直认为像这样的代码不是异常安全的,因为在delete异常的情况下不执行语句,因此unique_ptr应该使用其他类型的智能指针.但由于这是一个官方代码示例,我不确定这一点.所以:

以上代码示例异常是否安全?

小智 9

以上代码示例异常是否安全?

H**l不!

这就像你说的那样.您显示的代码在例外情况下像筛子一样泄漏.

std::unique应该使用RAII或指针.

即使对于预标准的c ++代码,也有好的std::auto_ptr.


但由于这是一个官方代码示例,我不确定这一点.

好吧,开源并不一定意味着它是任何"官方",或者无论如何"更好",而不是封闭的源代码,开发人员隐藏在客户眼中.

就这样.


嗯,公平(与MySQL贡献者):

这是一个最小的使用示例,当main()功能块退出并且进程终止时,将清除任何内存泄漏.

但不是一个真正的宝石一个很好的例子.鉴于许多平庸的程序员都在那里,并以"CTRL-C CTRL-V codez from teh samplez and tuz"为生,我不太确定这是一个好策略.


Conclusio:

不要盲目地复制和接管示例代码,即使不是来自图书馆,工具的官方文档页面或逐字逐句的代码.

这些意图是简化的,并且可以集中于库特征的使用而最少分散读者的注意力.

他们正在让你负责正确使用他们的东西.


我会怎么做才能解决它:

我考虑提供一个基于拥有和共享指针的瘦包装层作为简单的类成员(请参阅动态内存管理)和lambda函数:

class MySQLQuery;

class MySQLConnection {
    std::function<void(void*)> driverCleanup_;
    std::function<void>(void*) connectionCleanup_;
    std::unique_ptr<sql::Driver> driver_;
    std::shared_ptr<sql::Connection> con_;
public:
    MySQLConnection
        ( const std::string& ipAddress
        , const std::string& user
        , const std::string& password
        ) : 
        driverCleanup_([](void *driver) {
          // (sql::Driver*)driver->cleanup(); ## Whatever necessary
          delete driver;
        }) ,
        connectionCleanup_([](void *connection) {
          // (sql::Connection*)connection->cleanup();
          delete connection;
        }),
        driver_(get_driver_instance(),driverCleanup_),
        con_(std::make_shared(driver_->connect(ipAddress,user,password)
                             ,connectionCleanup_))
    {}

    std::unique_ptr<MySQLQuery> CreateQuery(const std::string& query);
};
Run Code Online (Sandbox Code Playgroud)
class MySQLQuery {
     friend class MySQLConnection;

     std::shared_ptr<sql::Connection> con_;
     std::unique_ptr<sql::Statement stmt_;
     MySQLQuery
       ( std::shared_ptr<sql::Connection> connection
       , const std::string& query
       ) : con_(connection) 
         , stmt_(con_->createStatement()
     {
     }
public:
     // And so on ...
     MySQLResultSet Execute() {
        return stmt_->executeQuery("SELECT 'Hello World!' AS _message");
     }
};
Run Code Online (Sandbox Code Playgroud)
std::unique_ptr<MySQLQuery> MySQLConnection::CreateQuery(const std::string& query) 
{
    return std::make_unique<MySQLQuery>(con_,query);
}
Run Code Online (Sandbox Code Playgroud)

此外,您可能会考虑在删除函数代码中捕获任何异常.虽然*从不(重新)从删除者那里抛出异常.这会让你搞砸一下.

harnished在所有种类的方向,如果成本低,始终是IMO是一个好主意.