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?
Related
Access to cloud that is of type boost:shared_ptr crashes with a Assertion failed: px != 0 error outside main, but inside main it is OK.
I am going to use PCL in a Qt program where I need to have access to a pointer to cloud outside the scope where this pointer is declared f.ex in MainWindow::classxyz() so I wrote this test program to illustrate my problem (see below)
How can I use a pointer correctly to be able to access the cloud pointer also outside the scope of main? (and Qt, outside the scope of MainWindow:MainWindow() as I will initialize the pointer in the constructor)
pcd_read.h:
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
void outside();
pcd_read.cpp:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include "pcd_read.h"
int
main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("C:/Users/user2/Documents/qt_test_kode_div/pcd_file_scope_test/build/Debug/test_pcd.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file test_pcd.pcd \n");
return (-1);
}
std::cout << "Loaded "
<< cloud->width * cloud->height
<< " data points from test_pcd.pcd with the following fields: "
<< std::endl;
std::cout << cloud->size(); //This works
outside(); //When I call outside() the code crashes inside outside()
for (size_t i = 0; i < cloud->points.size (); ++i)
std::cout << " " << cloud->points[i].x
<< " " << cloud->points[i].y
<< " " << cloud->points[i].z << std::endl;
return (0);
}
void outside()
{
std::cout << cloud->size(); // This crashes. Why does accessing cloud cause a crash related to Boost? Assertion failed: px != 0
// The pointer seems to not be initialized.
// I want the pointer to be accessible also in outside without passing as a parameter. How can I achieve that?
}
You declared another variable with the same name cloud inside main.
Therefore, the global one isn't visible inside main, and left unused, UNTIL you call outside, which then still refers to the unused global.
As #chrisD mentioned, changing the pointer initialization to a regular pointer solved it.
.h:
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; // original -- CRASHES OUTSIDE SCOPE - smartpointer ...
pcl::PointCloud<pcl::PointXYZ> *cloud; // changed to normal pointer -- now no crash ... since it is inside scope
void outside();
.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include "pcd_read.h"
int
main (int argc, char** argv)
{
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // Causes a crash when cloud is outside of scope
cloud = new pcl::PointCloud<pcl::PointXYZ>(); //Initializes pointer the std. way instead
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("C:/Users/user2/Documents/qt_test_kode_div/pcd_file_scope_test/build/Debug/test_pcd.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file test_pcd.pcd \n");
return (-1);
}
std::cout << "Loaded "
<< cloud->width * cloud->height
<< " data points from test_pcd.pcd with the following fields: "
<< std::endl;
std::cout << cloud->size(); //This works
outside();
for (size_t i = 0; i < cloud->points.size (); ++i)
std::cout << " " << cloud->points[i].x
<< " " << cloud->points[i].y
<< " " << cloud->points[i].z << std::endl;
return (0);
}
void outside()
{
std::cout << cloud->size(); // Now OK
I was trying to apply an iteration to my leveldb file, but unfortunately I couldn't get the result. The problem that I'm facing is a segmentation fault in using the pointer of the iterator. I used gdb And I got that the problem is in the line
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
(I added before some values to this file /tem/userDb , and the add is working good .)
#include <assert.h>
#include <leveldb/db.h>
#include <iostream>
#include <sstream>
using namespace std;
void iteration(leveldb::DB* db)
{
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next())
{
cout << "key :" << it->key().ToString() << " : "
<< "value:" << it - > value().ToString() << endl;
}
if (false == it->status().ok())
{
cerr << "An error was found during the scan" << endl;
cerr << it->status().ToString() << endl;
}
delete it;
}
int main(int argc, char *argv[])
{
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
// erase error if the database exists
options.error_if_exists = true;
leveldb::Status s = leveldb::DB::Open(options, "/tmp/userDb", &db);
if (!s.ok())
cerr << s.ToString() << endl;
iteration(db);
delete db;
}
Not familiar with the leveldb API, but you're using db regardless of whether s.ok() is true or false. I'd assume that if s.ok() is false, db is either NULL, or in a state such that iteration or other operations won't work.
You should change the code to:
if (!s.ok()) {
cerr << s.ToString() << endl;
return -1;
}
In php I create a config file that opens a connection to the database and then I use that file in all my other files in order to open a connection also. But I can't seem to find a way to do the same thing with c++. I can connect to the database but I can't use it as a class because I have a main() inside it and I can't seem to make it work without the main. This is my code:
// Standard C++ includes
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
// Include the Connector/C++ headers
#include "cppconn/driver.h"
#include "cppconn/exception.h"
#include "cppconn/resultset.h"
#include "cppconn/statement.h"
// Link to the Connector/C++ library
#pragma comment(lib, "mysqlcppconn.lib")
// Specify our connection target and credentials
const string server = "localhost";
const string username = "root";
const string password = "";
int main()
{
sql::Driver *driver; // Create a pointer to a MySQL driver object
sql::Connection *dbConn; // Create a pointer to a database connection object
sql::Statement *stmt; // Create a pointer to a Statement object to hold our SQL commands
sql::ResultSet *res; // Create a pointer to a ResultSet object to hold the results of any queries we run
// Try to get a driver to use to connect to our DBMS
try
{
driver = get_driver_instance();
}
catch (sql::SQLException e)
{
cout << "Could not get a database driver. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
// Try to connect to the DBMS server
try
{
dbConn = driver->connect(server, username, password);
}
catch (sql::SQLException e)
{
cout << "Could not connect to database. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
stmt = dbConn->createStatement();
// Try to query the database
try
{
stmt->execute("USE test");
res = stmt->executeQuery("SELECT * FROM users");
}
catch (sql::SQLException e)
{
cout << "SQL error. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
sql::ResultSetMetaData *res_meta = res -> getMetaData();
int columns = res_meta -> getColumnCount();
while (res->next())
{
for (int i = 1; i <= columns; i++) {
cout << res->getString(i) << " | " ;
}
cout << endl;
}
delete res;
delete stmt;
delete dbConn;
return 0;
}
You need to create a class (e.g class DBConnector)and declare functions in header file.
For example this piece of code can go into one function:
sql::Driver* DBConnector::GetDriverInstance()
{
try
{
m_driver = get_driver_instance();
}
catch (sql::SQLException e)
{
cout << "Could not get a database driver. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
return m_driver;
}
Here sql::Driver *m_driver is expected to be declared as a member variable of class in header file. You might need to read more about classes and member functions and variables before actually going ahead with code.
Other than this, you need to take very good care of memory management. I would suggest you read more and use smart pointers like std::shared_ptr.
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
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.