此C ++代码异常是否安全?

时间:2018-02-10 08:34:32

标签: 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;
}

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

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

1 个答案:

答案 0 :(得分:9)

  

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

H ** l no!

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

应使用RAII或sessionStorage['tabGUID']指针。

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

  

但由于这是官方代码示例,我对此不太确定。

嗯,开源并不一定意味着什么“官方”,或者无论如何“更好”而不是封闭的源代码,开发人员隐藏在客户的眼睛。

就是这样。

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

这是一个最小的用法示例,当std::auto_ptr功能块退出并且进程终止时,任何内存泄漏都会被清除。

但不是一个好的例子的 gem 。鉴于许多平庸的程序员都在那里,并以“CTRL-C CTRL-V codez from teh samplez and tuz”为生,我不太确定这是一个好策略。< / p>

Conclusio:

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

这些都是为了简化,可能会集中在图书馆功能的使用上,而读者最少分心。

他们非常<强烈>让你负责正确使用他们的东西。

我会做些什么来解决它:

我考虑提供一个基于拥有和共享指针的瘦包装层作为简单的类成员(参见Dynamic memory management)和lambda函数:

main()
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);
};
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");
     }
};

此外,您可能会考虑在删除函数代码中捕获任何异常。虽然 *从来没有(重新)抛出异常来自删除者。这会让你搞砸了。

如果费用很低,在所有方向上被玷污总是一个好主意IMO。