C ++ MySql Connector - результат запроса выходит из области видимости - PullRequest
0 голосов
/ 09 января 2019

У меня проблема с областями видимости результатов выполнения запроса соединителя C ++ mysql.

В приведенном ниже коде результат ResultSet * передается из другой функции, первоначально NULL; однако после выполнения строки result = statement->executeQuery( query ) результат больше не будет NULL.

Также из таблицы не выводятся ошибки.

Проблема возникает при возврате из этой функции. Результат ResultSet * переходит от не NULL к равенству NULL.

Ясно, что есть некоторая форма определения объема результатов SQL-запросов. Возможно, их функция возвращает ссылку на локальную переменную (на самом деле иначе не уверен)?

Как мне обойти эту проблему с ограничениями, чтобы классы / функции, вызывающие эту функцию, могли обращаться с результатами по своему усмотрению и уменьшить необходимость написания группы специализированных функций в этой оболочке? Кроме того, копии должны быть сведены к минимуму - следовательно, использование указателей.

bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet * result )
{

   //connection is a member variable and has been initialized
   sql::Statement * statement = connection->createStatement();

   try
   {
       result = statement->executeQuery( query );
   }
   catch( sql::SQLException &e )
   {
      //handle errors
   }

   delete statement;

   if( result == NULL )
   {
       printf( "Result is null File: %s Line %i\n", __FILE__, __LINE__ );
       return false;
   }
   else
   {
        printf("Result is not null File: %s Line %i\n", __FILE__, __LINE__ );
   }

   return true;
}

Если у меня есть функция foo, которая вызывает вышеуказанную функцию с правильными параметрами. printf о том, что результат не равен нулю, будет напечатан, но в foo, сразу после выполнения ExecuteQuery, указатель, переданный в функцию, станет NULL.

Ответы [ 2 ]

0 голосов
/ 09 января 2019
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet * result )
                                                                     ^^^^^^^^

Здесь результат очень похож на локальную переменную внутри функции и содержит копию переменной вызывающей стороны.

Когда вы присваиваете ему значение в ExecuteQuery, оно влияет только на переменную в функции, а не на переменную вызывающего.

Вместо этого вы можете сделать его ссылкой, поэтому он будет ссылаться на переменную вызывающего абонента следующим образом:

bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet *&result )

Другой подход заключается в передаче указателя на переменную (и поскольку переменная сама является указателем, вы будете иметь дело с указателем на указатель). Это позволяет вам также изменить указатель вызывающего абонента:

 bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet **result ) {
 ...
     *result = statement->executeQuery( query );

Это также требует модификации вызывающей стороны, поэтому он передает указатель на свою локальную переменную, например,

sql::ResultSet *rs;
c->ExecuteQuery("select ...", &rs);
0 голосов
/ 09 января 2019

Есть несколько проблем:

1. result передается по значению

Вы передаете result по значению. Это означает, что функция получает копию указателя, который вы передаете при вызове метода.

Например, если код, вызывающий ExecuteQuery, выглядит следующим образом:

std::string query("SELECT ...");
sql::ResultSet *result = NULL;
ExecuteQuery(query, result);

Тогда ExecuteQuery не может изменить значение result, так как оно КОПИРОВАННО в метод. Если вы хотите изменить его значение, вы должны передать ссылку на результат. Вы можете сделать это, изменив ExecuteQuery на:

bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet *& result )

Затем ExecuteQuery манипулирует исходным указателем, а не копией.

2. MySQL C ++ API освобождает ResultSet при удалении Statement

Точно так же, как указал @nos, когда вы звоните delete statement, вы также освобождаете ресурсы, которые содержат информацию для вашего result.

result будет по-прежнему иметь действительное значение, поскольку он не будет знать об освобожденной памяти, но если вы получите к ней доступ, это может вызвать ошибку сегментации.

Правильный способ справиться с этим - либо:

  • Скопировать результат
  • OR
  • Пусть вызывающая сторона также передает объект оператора и освобождает его после использования значения из результата.
...