我有一个下面定义的类:
class CVariable
{
public:
CVariable(CString strData, int nNum);
CVariable(BSTR bsData);
~CVariable();
public:
VARIANT GetVariant(){return m_bsVa;};
private:
VARIANT m_bsVa;
VARIANT m_nVa;
};
和工具是:
CVariable::CVariable(CString strData, int nNum)
{
VariantInit(&m_bsVa);
BSTR bsData = ::SysAllocString(strData);
m_bsVa.vt = VT_BSTR;
m_bsVa.bstrVal = bsData;
::SysFreeString(bsData);
VariantInit(&m_nVa);
m_nVa.vt = VT_I2;
m_nVa.lVal = nNum;
}
CVariable::CVariable(BSTR bsData) {
m_bsVa.vt = VT_BSTR;
m_bsVa.bstrVal = bsData;
}
CVariable::~CVariable()
{
VariantClear(&m_bsVa);
VariantClear(&m_nVa);
}
当我尝试使用构造函数
CVariable(CString,int)
构造两个实例时,类成员m_bsVas始终具有相同的值,而m_nVas不同。结果如下:
如您所见,v1和v2具有相同的m_bsVa但具有不同的m_nVa,而使用构造函数
CVariable(BSTR)
则得到正确的结果。我不知道为什么会这样?任何帮助将不胜感激。
最佳答案
我发现您的代码有几个问题。CVariable(CString, int)
构造函数为BSTR
分配m_bsVa
,但随后立即释放BSTR
,使m_bsVa
指向无效的内存,并允许下一个CVariable
实例为其使用潜在的重用相同的内存地址已分配BSTR
。您需要保留分配给BSTR
的权限,直到使用完m_bsVa
(或者至少要为其分配新的值)为止。 VariantClear()
将为您释放BSTR
。CVariable(BSTR)
构造函数根本没有初始化m_nVa
,这将对其后续的操作(包括VariantClear()
)造成问题。同样,构造函数正在获取调用方BSTR
的所有权。取决于您如何使用此构造函数,这可能可行,也可能不可行。如果呼叫者不希望您获得所有权,则需要使用BSTR
制作SysAllocString/Len()
的副本。VARIANT
不可复制。您需要使用VariantCopy()
函数将数据从一个VARIANT
复制到另一个。这意味着您的CVariable
类需要实现一个复制构造函数和一个复制赋值运算符。无论如何,您都需要执行该操作,以便您的类符合Rule of Three。GetVariant()
按原样返回m_bsVa
,因此编译器将按原样复制m_bsVa
字段的值到调用方的接收方VARIANT
中。由于BSTR
是指针,因此调用者将可以直接访问类内部的原始BSTR
。取决于您使用GetVariant()
的方式,这可能会也可能不会。在当前实现中,对返回的BSTR
的任何访问都应视为只读-调用方不得在其上调用SysFreeString()
,并且必须期望对CVariable
对象的任何更改都可能使BSTR
无效。如果那不符合您的需求,则GetVariant()
应该返回一个新的VARIANT
,该新的VariantCopy()
已通过VariantClear()
复制了数据,然后调用者可以在使用返回的VARIANT
完成后调用variant_t
。
话虽如此,请尝试类似以下的操作:
class CVariable
{
public:
CVariable(const CString &strData, int nNum);
CVariable(BSTR bsData);
CVariable(const CVariable &src);
~CVariable();
VARIANT GetVariant() const;
CVariable& operator=(const CVariable &src);
CVariable& operator=(BSTR src);
private:
VARIANT m_bsVa;
VARIANT m_nVa;
};
CVariable::CVariable(const CString &strData, int nNum)
{
::VariantInit(&m_bsVa);
m_bsVa.vt = VT_BSTR;
m_bsVa.bstrVal = ::SysAllocString(strData);
::VariantInit(&m_nVa);
m_nVa.vt = VT_I2;
m_nVa.lVal = nNum;
}
CVariable::CVariable(BSTR bsData)
{
::VariantInit(&m_bsVa);
m_bsVa.vt = VT_BSTR;
m_bsVa.bstrVal = bsData;
/* or this, if needed:
m_bsVa.bstrVal = ::SysAllocStringLen(bsData, ::SysStringLen(bsData));
*/
::VariantInit(&m_nVa);
}
CVariable::~CVariable()
{
::VariantClear(&m_bsVa);
::VariantClear(&m_nVa);
}
VARIANT CVariable::GetVariant() const
{
return m_bsVa;
/* or this, if needed:
VARIANT result;
::VariantInit(&result);
::VariantCopy(&result, &m_bsVa);
return result;
*/
}
CVariable& CVariable::operator=(const CVariable &src)
{
if (&src != this)
{
::VariantClear(&m_bsVa);
::VariantCopy(&m_bsVa, &src.m_bsVa);
::VariantClear(&m_nVa);
::VariantCopy(&m_nVa, &src.m_nVa);
}
return *this;
}
CVariable& CVariable::operator=(BSTR src)
{
::VariantClear(&m_bsVa);
m_bsVa.vt = VT_BSTR;
m_bsVa.bstrVal = src;
/* or this, if needed:
m_bsVa.bstrVal = ::SysAllocStringLen(src, ::SysStringLen(src));
*/
::VariantClear(&m_nVa);
return *this;
}
如果直接使用
VARIANT
类而不是,则可以大大简化代码,同时仍能解决上述所有要点:class CVariable
{
public:
CVariable(const CString &strData, int nNum);
CVariable(BSTR bsData);
variant_t GetVariant() const;
private:
variant_t m_bsVa;
variant_t m_nVa;
};
CVariable::CVariable(const CString &strData, int nNum)
: m_bsVa(strData), m_nVa(nNum)
{
}
CVariable::CVariable(BSTR bsData)
: m_bsVa(bsData)
{
}
variant_t CVariable::GetVariant() const
{
return m_bsVa;
}
关于c++ - 具有VARIANT成员的C++类对象具有奇怪的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40143927/