So I'm trying to build a class that connects to a mysql database and I want to connect in the constructor and catch exceptions to handle them and not construct the class. For reasons I won't go into I need it to work this way. I have found the error in the destructor of SQLConnection.cpp when it tries to delete a pointer. This pointer is instantiated from a MySQL connector library function and every tutorial and example I've seen has it deleted at the end. It doesn't seem right to me, but I couldn't find the documentation on the function to see why this delete was there. Also when I did delete this same pointer just running some tests in main it was fine (no seg fault).
Here is the important code so far
SQLConnection.h
#ifndef SQLCONNECTION_H
#define SQLCONNECTION_H
#include <mysql_connection.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
class SQLConnection{
private:
sql::Driver *driver;
const std::string IP;
const std::string user;
const std::string password;
void connect();
public:
sql::Connection *con;
SQLConnection();
SQLConnection(std::string inIP, std::string inUser, std::string inPassword);
~SQLConnection();
};
#endif
SQLConnection.cpp (the delete in the destructor causes the seg fault. When taken out it goes away. I'll show why I'm concerned with taking it out all together after this
#include "SQLConnection.h"
SQLConnection::SQLConnection() = default;
SQLConnection::SQLConnection(const std::string inIP, const std::string inUser, const std::string inPassword)
: IP(inIP), user(inUser), password(inPassword)
{
try
{
connect();
}
catch(...)
{
throw;
}
}
SQLConnection::~SQLConnection(){
if(con != nullptr){
delete con; //CAUSES SEG FAULT, when taken out program runs fine
}
}
void SQLConnection::connect(){
try{
driver = get_driver_instance();
con = driver->connect(IP, user, password);
}
catch (sql::SQLException &e) {
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << '\n';
std::cout << "# ERR: " << e.what() << '\n';
std::cout << "# ERR: MySQL error code: " << e.getErrorCode() << '\n';
}
if(con)
{
std::cout<<"Connected!" << "\n";
}
}
main.cpp
const std::string ip = "tcp://127.0.0.1:3306";
const std::string user = "IncorrectUser";
const std::string password = "IncorrectPass";
SQLConnection con1(ip, user, password);
std::cout << "still going" << '\n';
when this runs with incorrect login credentials it output
4 line of exceptions from catch block in connect
connected!
still going
segmentation fault (core dumped)
with correct credentials everything works fine
main.cpp without classes to test connection works fine
try{
driver = get_driver_instance();
con = driver->connect(IP, user, password);
}
catch(sql::SQLException &e){
std::cout << e.what() << '\n';
if(con){
std::cout << "connected!" << '\n';
}
delete con;
so I guess my main question is why is it saying connected if the constructor threw an exception shouldn't the class have never come into "existence". thus it shouldn't be saying connected and call it's destructor at the end of main causing the seg fault? Also If I need to use function level try catch in the constructor to fix this can someone give me a tip on how to call a member function from an initilization list. When I tried that before I got a compiler error saying
member field connect() does not exist
Related
At a point in my code, I pass a *this to a method foo(const MyClass& arg). An exception is thrown deep inside this foo, but although a syntactically correct try-catch block exists up the stack, it gets neither handled (a message should have been emitted in that case), nor the process crashes. From the debugging logs, I can see that related thread gets stuck, although the rest of the threads keep going.
I've been through stack unwinding documentation, and somewhere I've seen that arguments to functions are also considered to be auto variables, and get destroyed during the unwinding process. That brings me to the question: what happens when I pass a const reference of this (inside which there is a corresponding catch block) to a method where an exception is thrown? Is it possible that the ref gets the caller object destroyed, and catch block is now unreachable even though stack unwinding has begun already?
Let me add some pseudoish-code:
void MyClass0::someFunc(void)
{
try
{
MyClass1 obj1;
obj1.someOtherFunc(*this);
// Some other stuff
}
catch (MyException&)
{
std::cout << "Handling exception...";
// Whatever... This message is not emitted.
}
}
void MyClass1::someOtherFunc(const MyClass0& argObj0)
{
// Some functions that eventually throw an unhandled MyException
}
Thanks in advance...
EDIT:
OK, trying to generate an executable code for reference, I believe I pretty much answered my own question.
Here's the code:
#include "sandbox.h"
#include <iostream>
MyClass0::MyClass0(void)
{
std::cout << "\nConstructing MyClass0";
}
MyClass0::~MyClass0(void)
{
std::cout << "\nDestructing MyClass0";
}
void MyClass0::trustIssues(void)
{
std::cout << "\nEntering " << __FUNCTION__;
try
{
MyClass1 myClass1;
myClass1.unwaryFunction(*this);
}
catch (MyException& exc)
{
std::cout << "\nException caught in " << __FUNCTION__;
std::cout << "\nLeaving " << __FUNCTION__ << " from inside catch block.";
return;
}
std::cout << "\nLeaving " << __FUNCTION__;
}
MyClass1::MyClass1(void)
{
std::cout << "\nConstructing MyClass1";
}
MyClass1::~MyClass1(void)
{
std::cout << "\nDestructing MyClass1";
}
void MyClass1::unwaryFunction(MyClass0& argClass0)
{
std::cout << "\nEntering " << __FUNCTION__;
suicidalFunction();
std::cout << "\nLeaving " << __FUNCTION__;
}
void suicidalFunction(void)
{
std::cout << "\nEntering " << __FUNCTION__;
MyException myException;
throw myException;
std::cout << "\nLeaving " << __FUNCTION__;
}
int main(int argc, char* argv[])
{
MyClass0 myClass0;
myClass0.trustIssues();
return 0;
}
The output has been:
Constructing MyClass0
Entering MyClass0::trustIssues
Constructing MyClass1
Entering MyClass1::unwaryFunction
Entering suicidalFunction
Destructing MyClass1
Exception caught in MyClass0::trustIssues
Leaving MyClass0::trustIssues from inside catch block.
This implies that the *this argument does not get destroyed on stack unwinding of unwaryFunction. I probably have some other bug in the actual code (as the message analogous to "Exception caught in..." does not get printed). I'll keep this question for future reference. Thanks for your concern anyway.
It show error code : Can't create socket(24) , after I survey I know that is reach the open_files_limit,I checked the show global variables like 'open%';
in MySQL and value is 5000000,so my code must some problem in it.
here's my simple code:
class DB {
public:
double query1();
double query2();
double query3();
};
main() {
DB handler;
for(int i=0;i<100000;i++) {
handler.query1();
handler.query2();
handler.query3();
}
}
I wrote a class handle the 3 query and run it in the loop, how can I prevent open-file limit problem in this class
here's query code :
double query1(string pair) {
double get_prob;
try {
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("localhost", "root", "nlpgroup");
/* Connect to the MySQL test database */
con->setSchema("em_im");
stmt = con->createStatement();
stringstream stmvar;
stmvar << "select prob from em where pair='" << pair << "'";
string stmvarstr = stmvar.str();
cout << stmvarstr << endl;
res = stmt->executeQuery(stmvarstr); // replace with your statement
while (res->next()) {
get_prob = atof(res->getString(1).c_str());
}
res->close();
stmt->close();
con->close();
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;
}
return get_prob;
}
show global variables like 'open%'; in MySQL
Apart from MySQL, your OS might impose limits, too. For linux, have a look at /etc/security/limits.conf, on Windows, this answer might help you out.
However, if you need one and the same connection that often one after another time, it might be a better choice to open it once and keep it open until your program terminates. This will additionally give you better performance - and you can improve performance even more using a prepared statement instead. I added this to the example below already...
class DB
{
std::unique_ptr <sql::Connection> con;
std::unique_ptr <sql::PreparedStatement> stmt;
public:
DB();
double query1(std::string const& pair);
};
DB::DB()
: con(get_driver_instance()->connect("localhost", "root", "nlpgroup"))
{
con->setSchema("em_im");
// you might prefer a prepared statement
stmt.reset(con->prepareStatement("SELECT prob FROM em WHERE pair = ?"));
}
double DB::query1(std::string const& pair)
{
double get_prob = 0.0;
try
{
stmt->setString(1, pair);
std::unique_ptr < sql::ResultSet > res(stmt->execute());
while (res->next())
{
get_prob = atof(res->getString(1).c_str());
}
}
catch(sql::SQLException& e)
{
/* ... */
}
return get_prob;
}
Usage of std::unique_ptr assures that all objects are deleted correctly even in case of an exception - which, by the way, your code did not. I did not call close explicitely - it will be called in the objects' destructors anyway, so this is fine.
Be aware that now the constructor can throw an exception, too, so you need a try - catch in the main function, too. Depending on your needs, you then could leave out the try - catch in the query functions. This changes behaviour, however: Leaving as is results in all the queries being executed, even if one fails in between, whereas dropping it results in aborting the loop.
I have written a program using C++/C, the MySQL C++ connector and ncurses/CDK. It compiles just fine, and runs fine as well on an x86/64 architecture. It crashes, however, when run on a Raspberry Pi B+ (ArchLinux).
I realize this is a pretty hard question to answer, but maybe someone more experienced can help.
Here's the (hopefully) relevant Code:
//Open Connection to the Database
nrpeout::MYSQL_CON localhost("127.0.0.1", 3306, "root", "toor");
//localhost.write_attributes_to_console();
con = localhost.open_database_connection();
//Create a new object of type nrpeoutputquery
nrpeout::Nrpeoutputquery current_query("SELECT * FROM nrpeout", con);
//Execute query
res = current_query.execute_query();
//Close Database Connection
localhost.close_database_connection(con);
} catch (sql::SQLException &e) {
//Handle SQL-Exceptions
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line "
<< __LINE__ << std::endl;
std::cout << "# ERR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
} catch(...) {
//Handle Standard Exceptions
std::cout << "Unknown Exception raised. Please contact your Administrator" << std::endl;
}
nrpeout::NrpeResultSet* currentResults = new nrpeout::NrpeResultSet(res);
Using Valgrind and GDB, I have tried to narrow the error down to the line where I create the object "currentResults".
Here's the member function that saves the query results:
nrpeout::NrpeResultSet::NrpeResultSet(sql::ResultSet* res)
{
for (unsigned int i = 0; i < res->rowsCount(); ++i)
{
res->next();
std::string command = res->getString("command");
//Shorten the String
size_t posCommand = command.find("_");
std::string shortened_command = command.substr(posCommand+1);
int ret = res->getInt("ret");
std::string text = res->getString("text");
//Shorten the Text
size_t posText = text.find("|");
std::string shortened_text = text.substr(0, posText-1);
std::string last_updated = res->getString("last_updated");
this->results.push_back(Row(shortened_command, ret, shortened_text, last_updated));
}
Well, you are not catching an exception, which you may want to handle. InvalidInstanceException is thrown when using closed databse connections, statements or resultsets.
My suggestion is to run your code with a gdb and catch exceptions:
gdb ./some-program
$ catch throw
$ r
This will break after each exception being thrown. (But also includes handled exceptions, so there may be quite a few breaks, depending on how long it takes you to get to the important part.)
I'm using my own Exception class that inherits from std::exception. I'm pretty sure the class is okay since it has always worked up until now. I'm trying to throw an error from a constructor:
DataBase::DataBase()
: _result(NULL)
{
mysql_init(&_mysql);
mysql_options(&_mysql,MYSQL_READ_DEFAULT_GROUP,"option");
if(!mysql_real_connect(&_mysql,"localhost","root","","keylogger",0,NULL,0))
throw Exception(__LINE__ - 1, __FILE__, __FUNCTION__, "Can't connect to DB");
}
Here is my try/catch block :
int main(int, char **)
{
//[...]
Server server([...]); // DB is a private member in Server
try
{
server.fdMonitor();
}
catch (Exception &e)
{
std::cout << "Error: in " << e.file() << ", " << "function " << e.function()
<< "(line " << e.line() << ") : " << std::endl
<< "\t" << e.what() << std::endl;
}
return (1);
}
The problem is that the Exception thrown from my DB constructor isn't caught. Here's the abort message:
terminate called after throwing an instance of 'Exception'
what(): Can't connect to DB
Aborted
Any ideas?
Thanks in advance.
From your description, it sounds like the DataBase constructor is called from the Server constructor.
So, you need to move that line into the try block :
try
{
Server server([...]); // DB is a private member in Server
server.fdMonitor();
}
catch (Exception &e)
{
// ...
}
The problem is that the place which throws (construction of server) is not within the try block.
My destructor is not being called when the program exits. The object is a singleton, perhaps I am missing something?
Here is the header and cpp file:
#ifndef MYSQLCONNECTOR_H
#define MYSQLCONNECTOR_H
/* Standard C++ headers */
#include <iostream>
#include <string>
/* MySQL Connector/C++ specific headers */
#include <driver.h>
#include <connection.h>
#include <statement.h>
#include <prepared_statement.h>
#include <resultset.h>
#include <metadata.h>
#include <resultset_metadata.h>
#include <exception.h>
#include <warning.h>
class MysqlConnector {
private:
static bool instanceFlag;
static MysqlConnector* mysqlConnector;
MysqlConnector() {
};
public:
static sql::Driver *driver;
static sql::Connection *conn;
static MysqlConnector* getInstance();
virtual ~MysqlConnector() {
instanceFlag = false;
conn->close();
delete conn;
std::cout << "called" << std::endl;
};
private:
};
#endif /* MYSQLCONNECTOR_H */
And the cpp file
#include "MysqlConnector.h"
using namespace std;
using namespace sql;
bool MysqlConnector::instanceFlag = false;
MysqlConnector* MysqlConnector::mysqlConnector = NULL;
MysqlConnector* MysqlConnector::getInstance() {
if (!instanceFlag) {
mysqlConnector = new MysqlConnector();
instanceFlag = true;
try {
driver = get_driver_instance();
/* create a database connection using the Driver */
conn = driver->connect("tcp://127.0.0.1:3306", "root", "root");
/* turn off the autocommit */
conn -> setAutoCommit(0);
/* select appropriate database schema */
conn -> setSchema("exchange");
} catch (SQLException &e) {
cout << "ERROR: SQLException in " << __FILE__;
cout << " (" << __func__ << ") on line " << __LINE__ << endl;
cout << "ERROR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << ")" << endl;
if (e.getErrorCode() == 1047) {
cout << "\nYour server does not seem to support Prepared Statements at all. ";
cout << "Perhaps MYSQL < 4.1?" << endl;
}
} catch (std::runtime_error &e) {
cout << "ERROR: runtime_error in " << __FILE__;
cout << " (" << __func__ << ") on line " << __LINE__ << endl;
cout << "ERROR: " << e.what() << endl;
}
return mysqlConnector;
} else {
return mysqlConnector;
}
}
Your destructor is not getting called because nobody is calling delete for an object created with new:
mysqlConnector = new MysqlConnector(); // Where's the corresponding call to delete?
You may consider using a smart pointer instead (I would suggest std::unique_ptr, if you can afford C++11). That would automatically called delete on the encapsulated object when the smart pointer itself is destroyed.
Another possibility is to not use pointers at all, and have a static data member of type MysqlConnector. getInstance() could then return a reference (rather than a pointer) to that object.
static MysqlConnector* mysqlConnector;
Is the pointer to the class. When you get the instance it just returns this pointer. You need to call delete on this static pointer for the destructor to be called.
If you do go ahead and call delete on this pointer, make sure you only do so when the program terminates though - since the next call to getInstance() will create a new object.
EDIT - just spotted the instanceFlag so it won't create a new instance but would return a NULL pointer
This is problematic since you might expect the Singleton to be the same object, but of course creating a new instance of it will mean that your data will not be persistent (even though you are accessing a singleton).
The OS will reclaim the memory regardless, so you might be better to expose the connection closing code and calling that by yourself?