ここには 2 つの問題があります。1 つは必要なクエリを含む文字列を作成することであり、もう 1 つはその文字列を引数として関数に渡すことです。
これらの C の境界に到達するまでは、できるだけ "C++" のままにすることをお勧めします。したがってstd::wstring
、C スタイルの文字列にする必要があるポイントまで、文字列処理に使用する必要があります。
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(statementText.c_str()), SQL_NTS);
c_str()
メンバー関数はヌル終了配列 (つまり、C スタイルの文字列) へのポインターを返しますが、このポインターの型は;const wchar_t*
です。つまり、この C スタイルの文字列の内容は変更できません。
これは問題SQLWCHAR*
ですwchar_t*
。データをそのままにしておくことを約束するものではありません。そのため、値からconst_cast
を削除するために ,を含めました。const
c_str()
これは、一般的にやりたいことではありません。 const_cast
const オブジェクトを変更するのは UB であるため、未定義の動作への扉を直接開くため、間違いなく最も恐ろしいキャストです。
const int x = 0;
const int* p = &x; // anyone using this pointer can't modify x
int* bad = const_cast<int*>(p); // but this one is not so good
*bad = 5; // undefined behavior
ただし、ここで問題ない理由は、渡された文字列を実際にSQLExecDirect
変更しないためです。const が使用されていないのは単に実装エラーであるため、削除しても問題ありません。(この const の欠如の間違いは、C では非常に一般的です。)
変更可能なバッファが本当に必要な場合は、現在のバージョンの C++ (C++11) から始めて、これを安全に行うことができます。
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, &statementText[0], SQL_NTS);
最初の要素のアドレスを取得しています。これは、それ自体が null で終了する配列にあります。別の C スタイルの文字列。ただし、今回は変更可能な配列があります。タイプはすでに一致しています。
(これが C++11 で問題ないことに注意する理由は、以前のバージョンである C++03 では技術的にこの動作が保証されていなかったためです。そうではありません.実用的には、どちらの方法でも問題ありません.)
どちらを使用するかはあなた次第です。常に使用するだけだと主張する人もいる&str[0]
ので、UBは絶対にありません。関数が文字列を変更してconstをキャストするのではなく、最終的にconstの考え方で動作するという意図と信念を文書化することを主張します。何か悪いことが起こった場合、 const を付けておけばよかったと思うよりも、 const から離れてリラックスするのは簡単です。
注意すべき重要な点の 1 つは、これらの返されたすべてのポインター ( または のいずれstr.c_str()
か&str[0]
) は、str
オブジェクト自体が生きていて変更されていない場合にのみ有効であるということです。これは悪いです:
const wchar_t* get_query()
{
std::wstring result = /* build query */;
// oops, this pointer stops being meaningful when result stops existing!
return result.c_str();
}
邪魔にならないので、これらの文字列を構築するのは簡単です。std::wstringstream
: _
std::wstringstream ss;
ss << "this is basically an expanding buffer that accepts anything std::wcout will";
ss << std::endl;
ss << "this includes integers " << 5 << " and other stream-insertable types";
したがって、おそらく次のようなものが必要です。
std::wstring build_query(const std::wstring& name)
{
// you can provide a starting string
std::wstringstream result(L"select * from DB.employees where lname=");
result << "\'" << name << "\'";
return result.str(); // this captures the buffer as a C++ string
}
// Remember, this would be bad!
//
// SQLWCHAR* SQL = const_cast<SQLWCHAR*>(build_query(L"Smith").c_str());
//
// Because the C++ string returned by build_query is temporary;
// it stops existing at the end of this full expression,
// so SQL would be a bad pointer. This is right:
std::wstring SQL = build_query(L"Smith");
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS);
それが役立つことを願っています。
また、マクロを除いてすべて大文字の識別子を使用することは避けたいと思います。なぜなら、C++ コードを読む人は、そのような名前が圧倒的にマクロであると予想しているからです。さらに、サンプル コードでは C++ スタイルのキャストを使用しました。あなたは同じことをすべきです。C スタイルのキャスト ( (type)value
) は、強力すぎて安全ではありません。