
有同學做類似如下的操作:
class X
{
public:
X() // 類X的構造函數ctor
_mysql_handler = mysql_init(NULL);
}
};
// 定義類X的全局變量
X g_x;
// 程式入口main函數
int main()
。。。 。。。
看似簡單的代碼,但非常不幸,程式運作時,卡在了mysql_init處。文法上看不出任何破綻,原因會是什麼了?
#define g_x x_ref()
X& x_ref()
static X x; // 技巧就在這裡
return x;
當然,良好的習慣是盡量避免使用全局變量,實在無法避免時(如考慮到結構的複雜性),則可以考慮用上述方法規避全局變量互依賴産生的問題。
附1:mysql_init源碼
/****************************************************************************
Init MySQL structure or allocate one
****************************************************************************/
MYSQL * STDCALL
mysql_init(MYSQL *mysql)
if (mysql_server_init(0, NULL, NULL))
return 0;
if (!mysql)
{
if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
{
set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate);
return 0;
}
mysql->free_me=1;
}
else
memset(mysql, 0, sizeof(*(mysql)));
mysql->charset=default_client_charset_info;
strmov(mysql->net.sqlstate, not_error_sqlstate);
/*
Only enable LOAD DATA INFILE by default if configured with
--enable-local-infile
*/
#if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
#endif
#ifdef HAVE_SMEM
mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name;
mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
mysql->options.report_data_truncation= TRUE; /* default */
By default we don't reconnect because it could silently corrupt data (after
reconnection you potentially lose table locks, user variables, session
variables (transactions but they are specifically dealt with in
mysql_reconnect()).
This is a change: reconnect was set to 1 by default.
How this change impacts existing apps:
- existing apps which relyed on the default will see a behaviour change;
they will have to set reconnect=1 after mysql_real_connect().
- existing apps which explicitely asked for reconnection (the only way they
could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
will not see a behaviour change.
- existing apps which explicitely asked for no reconnection
(mysql.reconnect=0) will not see a behaviour change.
mysql->reconnect= 0;
mysql->options.secure_auth= TRUE;
return mysql;
附2:mysql_server_init源碼
/*
Initialize the MySQL client library
SYNOPSIS
mysql_server_init()
NOTES
Should be called before doing any other calls to the MySQL
client library to initialize thread specific variables etc.
It's called by mysql_init() to ensure that things will work for
old not threaded applications that doesn't call mysql_server_init()
directly.
RETURN
0 ok
1 could not initialize environment (out of memory or thread keys)
*/
int STDCALL mysql_server_init(int argc __attribute__((unused)),
char **argv __attribute__((unused)),
char **groups __attribute__((unused)))
int result= 0;
if (!mysql_client_init)
mysql_client_init=1;
org_my_init_done=my_init_done;
if (my_init()) /* Will init threads */
return 1;
init_client_errs();
if (mysql_client_plugin_init())
if (!mysql_port)
char *env;
struct servent *serv_ptr __attribute__((unused));
mysql_port = MYSQL_PORT;
/*
if builder specifically requested a default port, use that
(even if it coincides with our factory default).
only if they didn't do we check /etc/services (and, failing
on that, fall back to the factory default of 3306).
either default can be overridden by the environment variable
MYSQL_TCP_PORT, which in turn can be overridden with command
line options.
*/
#if MYSQL_PORT_DEFAULT == 0
if ((serv_ptr= getservbyname("mysql", "tcp")))
mysql_port= (uint) ntohs((ushort) serv_ptr->s_port);
if ((env= getenv("MYSQL_TCP_PORT")))
mysql_port=(uint) atoi(env);
if (!mysql_unix_port)
#ifdef __WIN__
mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
#else
mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
if ((env = getenv("MYSQL_UNIX_PORT")))
mysql_unix_port = env;
mysql_debug(NullS);
#if defined(SIGPIPE) && !defined(__WIN__)
(void) signal(SIGPIPE, SIG_IGN);
#ifdef EMBEDDED_LIBRARY
if (argc > -1)
result= init_embedded_server(argc, argv, groups);
result= (int)my_thread_init(); /* Init if new thread */
return result;