gpt4 book ai didi

c++ - 具有 VARIANT 成员的 VC++ 类对象具有奇怪的行为

转载 作者:行者123 更新时间:2023-11-28 05:27:59 25 4
gpt4 key购买 nike

我在下面定义了一个类:

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_bsVa始终具有相同的值,而m_nVa则不同。结果如下: enter image description here

如您所见,v1v2 具有相同的 m_bsVa 但不同的 m_nVa,同时使用构造函数 CVariable(BSTR) 导致正确结果。我不知道为什么会这样?任何帮助将不胜感激。

最佳答案

我发现你的代码有几个问题。

  1. CVariable(CString, int) 构造函数为 m_bsVa 分配一个 BSTR,然后释放 BSTR 立即离开 m_bsVa 指向无效内存,并允许下一个 CVariable 实例可能为其分配的 BSTR 重用相同的内存地址.您需要保留分配的 BSTR,直到您使用完 m_bsVa(或者至少直到您想要为其分配一个新值)。 VariantClear() 将为您释放 BSTR

  2. CVariable(BSTR) 构造函数根本没有初始化 m_nVa,这将导致后续操作出现问题,包括 VariantClear() 。此外,构造函数正在取得调用者的 BSTR 的所有权。这可能可行也可能不可行,具体取决于您如何使用此构造函数。如果调用者不希望您获得所有权,那么您需要使用 SysAllocString/Len() 复制 BSTR

  3. VARIANT 不可简单复制。您需要使用 VariantCopy() 函数将数据从一个 VARIANT 复制到另一个。这意味着您的 CVariable 类需要实现复制构造函数和复制赋值运算符。无论如何你都需要这样做,这样你的类(class)就符合 Rule of Three .

  4. GetVariant() 按原样返回 m_bsVa,因此编译器将简单地复制 m_bsVa 字段的值按原样进入调用者的接收 VARIANT。由于 BSTR 是一个指针,调用者可以直接访问您类中的原始 BSTR。这可能可行也可能不可行,具体取决于您如何使用 GetVariant()。在当前的实现中,对返回的 BSTR 的任何访问都应被视为只读 - 调用者不得对其调用 SysFreeString() ,并且必须预料到 CVariable 对象的任何更改可能会使 BSTR 无效。如果这不符合您的需要,那么 GetVariant() 应该返回一个新的 VARIANT,它已经通过 VariantCopy() 复制了数据,然后调用者可以使用返回的 VARIANT 调用 VariantClear()

话虽如此,尝试更像这样的事情:

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_t类而不是直接使用 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 成员的 VC++ 类对象具有奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40143927/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com