Boost 共有ポインタに問題があります。ポインターが指すデータは、不確定な時間に突然削除されます。現在のプログラム (私は他の多くのバリエーションを試しました) では、ループが正確に 172 行 (テーブルには 1000 行あります) を実行したboost::shared_array<TableFieldsMap> retArray
後、ケース case の後、switch 構築でデータが突然削除されます。MYSQL_TYPE_DOUBLE
ただし、メソッドが 2 回呼び出された場合のみです。最初の実行は完全に機能します。
具体的には、retArray への割り当てで使用されている map-key に問題があることを突き止めました。ハードコードされた文字列を使用したときに機能します。しかし、ローカルの shared_array (fieldNameArray) の値ではなく (私は最初に scoped_array を持っていましたが、これは機能しないはずです)、ローカル変数 (tmpIndex) ではありません。
retArray[rowIndex]["value"] = boost::lexical_cast<long double>(row[i]); // This works.
// This doesn't work: retArray[rowIndex][fieldNameArray[i]] = boost::lexical_cast<long double>(row[i]);
// This doesn't work either: retArray[rowIndex][tmpIndex.c_str()] = boost::lexical_cast<long double (row[i]);
ヘッダークラスは次のとおりです。
#ifndef DATABASE_H
#define DATABASE_H
#include <map>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
#include <glog/logging.h>
#include <boost/lexical_cast.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/variant.hpp>
#include <mysql.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include "../globals/globals.hpp"
#include "../exception/cassandra_exception.hpp"
struct mapCompare
{
bool operator()(char const * a, char const * b)
{
return (strcmp(a, b) < 0);
}
};
typedef map<const char*, boost::variant<short, int, long double, char*>, mapCompare > TableFieldsMap;
struct DataSet
{
unsigned int rowCount;
boost::shared_array<TableFieldsMap>data;
};
class Database
{
private:
MYSQL *connection;
public:
Database();
~Database();
bool connect(const char *, const char *, const char *, const char *);
DataSet select(const char*);
};
#endif
そしてコード:
#include "database.hpp" Database::Database() { DLOG(INFO) << "::Database"; } Database::~Database() { DLOG(INFO) << "~Database"; if (connection) mysql_close(connection); } bool Database::connect(const char* server, const char* user, const char* password, const char* database) { DLOG(INFO) << ">> connect"; connection = mysql_init(NULL); if (!connection) { cout << "Error" << endl; return (false); } if (!mysql_real_connect(connection, server, user, password, database, 0, NULL, 0)) { cout << "Database init error (" << mysql_error(connection) << ")" << endl; } if (!connection) { cout << "Connection Failed!" << endl; return (false); } return (true); } DataSet Database::select(const char* query) { DLOG(INFO) << ">> select"; MYSQL_RES *resultSet; MYSQL_ROW row; unsigned int fieldCount; MYSQL_FIELD* field; // Query database. if (mysql_query(connection, query)) throw MyException(string("Database select error (") + mysql_error(connection) + ")"); // Handle result-set. resultSet = mysql_store_result(connection); if (resultSet == NULL) throw MyException(string("Database select error. Result-set is empty (") + mysql_error(connection) + ")"); // Initialize return array. unsigned int rowCount = mysql_num_rows(resultSet); boost::shared_array<TableFieldsMap> retArray(new TableFieldsMap[rowCount]); // Obtain field names and types. fieldCount = mysql_num_fields(resultSet); boost::shared_array<const char *> fieldNameArray(new const char* [fieldCount]); boost::scoped_array<enum_field_types> fieldTypeArray(new enum_field_types[fieldCount]); unsigned int fieldIndex = 0; while ((field = mysql_fetch_field(resultSet))) { fieldNameArray[fieldIndex] = field -> name; fieldTypeArray[fieldIndex++] = field -> type; } // Fix? string tmpIndex; // Load data from result-set. unsigned int rowIndex = 0; while ((row = mysql_fetch_row(resultSet)) != NULL) { // Fields of the row. for (unsigned int i = 0; i < fieldCount; i++) { if (row[i] == NULL) throw MyException("Database error. Null."); switch (fieldTypeArray[i]) { // Medium int & Integer. case MYSQL_TYPE_INT24 : case MYSQL_TYPE_LONG : retArray[rowIndex][fieldNameArray[i]] = boost::lexical_cast<int>(row[i]); break; case MYSQL_TYPE_DOUBLE : try { retArray[rowIndex]["value"] = boost::lexical_cast<long double>(row[i]); // This works. } catch (boost::bad_lexical_cast exception) { DLOG(ERROR) << "Error reading the phi table from database. Cast error. (" << rowIndex << ", " << row[i] << ")" << endl; throw MyException("Error reading the phi table from database. Cast error."); } // tmpIndex = string(fieldNameArray[i]); // This doesn't work: retArray[rowIndex][fieldNameArray[i]] = boost::lexical_cast<long double>(row[i]); // This doesn't work either: retArray[rowIndex][tmpIndex.c_str()] = boost::lexical_cast<long double>(row[i]); break; case MYSQL_TYPE_VARCHAR : // 15 case MYSQL_TYPE_VAR_STRING : // 253 case MYSQL_TYPE_STRING : // 254 retArray[rowIndex][fieldNameArray[i]] = row[i]; break; case MYSQL_TYPE_DECIMAL : // 0 case MYSQL_TYPE_TINY : // 1 case MYSQL_TYPE_SHORT : // 2 case MYSQL_TYPE_FLOAT : // 4 case MYSQL_TYPE_NULL : // 6 case MYSQL_TYPE_TIMESTAMP : // 7 case MYSQL_TYPE_LONGLONG : // 8 case MYSQL_TYPE_DATE : // 10 case MYSQL_TYPE_TIME : // 11 case MYSQL_TYPE_DATETIME : // 12 case MYSQL_TYPE_YEAR : // 13 case MYSQL_TYPE_NEWDATE : // 14 case MYSQL_TYPE_BIT : // 16 case MYSQL_TYPE_NEWDECIMAL : // 246 case MYSQL_TYPE_ENUM : // 247 case MYSQL_TYPE_SET : // 248 case MYSQL_TYPE_TINY_BLOB : // 249 case MYSQL_TYPE_MEDIUM_BLOB : // 250 case MYSQL_TYPE_LONG_BLOB : // 251 case MYSQL_TYPE_BLOB : // 252 default: DLOG(FATAL) << "Database error. Unsupported datatype"; throw MyException("Database error. Unsupported datatype"); break; } rowIndex++; } } mysql_free_result(resultSet); DataSet retStruct; retStruct.rowCount = rowCount; retStruct.data = retArray; return (retStruct); }
...
呼び出し方法は次のとおりです。
include "My_database.hpp"
MyDatabase::MyDatabase(string server, string user, string password, string database)
{
DLOG(INFO) << "::MyDatabase (1)";
init(server.c_str(), user.c_str(), password.c_str(), database.c_str());
}
MyDatabase::MyDatabase(const char* server, const char* user, const char* password, const char* database)
{
DLOG(INFO) << "::MyDatabase (2)";
init(server, user, password, database);
}
MyDatabase::~MyDatabase()
{
DLOG(INFO) << "~MyDatabase";
}
void MyDatabase::init(const char* server, const char* user, const char* password, const char* database)
{
DLOG(INFO) << ">> init";
connect(server, user, password, database);
}
boost::shared_array<long double>MyDatabase::loadPhiTable()
{
DLOG(INFO) << ">> LoadPhiTable";
// Select from database.
DataSet selectData = select("SELECT value FROM phi");
boost::shared_array<TableFieldsMap>phiArray = selectData.data;
unsigned int rowCount = selectData.rowCount;
// Initialize return array.
boost::shared_array<long double> retArray(new long double[rowCount]);
unsigned int i = 0;
try
{
for (i = 0; i < rowCount; i++) retArray[i] = boost::get<long double>(phiArray[i]["value"]);
}
catch (boost::bad_get exception)
{
throw MyException(string("Error reading the phi table. Conversion error. (index: ") + boost::lexical_cast<string>(i) + ", value: " + boost::lexical_cast<string>(phiArray[i]["value"]) + ")");
}
return (retArray);
}
他の提案もいただければ幸いです。私の最初の C++ プログラム。