MFC:std::string与CString有何区别?

25

使用C++和MFC。由于我之前主要使用C#,所以通常会对所有字符串都使用string。我将它们用作类成员、方法参数和方法返回值。

现在在C++中,有std::string、CString、char *、LPCTSTR等等。在设计数据成员、方法参数和方法返回值时应该使用哪种类型?易用性很重要,而CString似乎提供了这种易用性,但我的直觉是朝着可移植标准的方向,尽管可移植性在我目前的优先事项列表中并不是太重要。另外,我不喜欢创建字符串缓冲区并将其传递到方法和函数中的C语义。

从立即编码的角度来看,CString可能更容易使用。但总体而言,什么是“高代码质量”的方法呢?

编辑:

我特别关注代码中的接口点(例如,方法参数和返回值)。例如:

Shape::SetCaption(const char *caption) {...}

Shape::SetCaption(CString caption) {...}

Shape::SetCaption(std::string caption) {...}

Shape::SetCaption(std::wstring caption) {...}

@Christian:正在为一个使用MFC实现的平台编写插件,并且必须与其紧密集成。我尝试了Qt,但Qt/MFC集成是一场艰苦的战斗。如果有选择的话,我会选择C#。 - User
同意Christian Rau的评论。 MFC不是一个开发者友好的框架。QT更简单地实现GUI。 - Moses
4个回答

24

我通常喜欢根据我所使用的框架来调整我的编程风格,以保持一致性。因此,当我使用MFC(已经很久没有使用了)时,我更喜欢使用CString(以及在公共接口方法中作为函数参数的LPCTSTR)。当我使用Qt时,我更喜欢使用QString和Qt的容器,而不是STL容器;对于与这种框架没有直接关系的所有内容,我使用std::string,因为这是处理字符串的C++标准方式。

它们都提供了大致相等的功能(并且可以很容易地相互转换),所以它们之间并没有太大的区别,而且当代码针对某个框架编写时,它就依赖于该框架,因此可移植性不是太重要。

只是不要再使用普通的字符数组!顺便说一下,尽量通过const引用传递对象(const std::string &caption),而不是按值传递,因为在C++中,变量不会自动成为引用,复制一个字符串可能会非常昂贵。


有时候我需要一个临时缓冲区,所以我会使用普通的char数组,不过我也用过vector<char>,效果不错。 - Mark Ransom
有道理,但是即使在您构建的静态库中,您是否会在您的MFC项目中使用CString? - User
如果该库本身不使用或依赖于MFC,并且可能与另一个项目一起使用,那么肯定不会。但是如果它已经与您的项目绑定在一起,我不太确定。我会在与MFC无直接关系的所有内容中使用std::string以获得更好的代码重用性和灵活性。 - Christian Rau

9

MFC是希望您使用CString的。这一点尤其在函数使用参数返回字符串时更为明显。例如,比较一下这两个对GetWindowText的调用:

CString s1;
wnd.GetWindowText(s1);

std::wstring s2(SOME_MAX, 0);
int len = wnd.GetWindowText(&s2[0], s2.size());
s2.resize(len);

两者之间的转换并不难,因此您可以通过在大多数情况下使用std :: wstring和在必要时使用临时CString来妥协。

CString s3 = s2.c_str();
std::wstring s4 = s1;

编辑:或许有一种方法可以自动化临时CString。但需要提醒的是,这是一个完全的hack。我没有尝试过,所以不能保证 - 你可能会收到关于将临时对象绑定到非const引用的警告,但你可以关闭这些警告。

class PopString : public CString
{
public:
    PopString(std::wstring & final) : m_final(final)
    {
    }

    ~PopString()
    {
        m_final = (PCTSTR) *this;
    }
private:
    PopString(const PopString &) {}  // private copy constructor to prevent copying
    PopString & operator=(const PopString &) {}  // private copy operator

    std::wstring & m_final;
};

std::wstring s5;
wnd.GetWindowText(PopString(s5));

3
如果您关心可移植性并且使用C ++,请使用std :: string 。如果不需要,没有必要使用char数组进行低级别操作。如果您不关心可移植性,并且平台提供的字符串提供了更多所需功能,请放心使用。它们实际上可能会为平台进行更多优化。

1
从技术上讲,应该使用std :: basic_string <>,而不仅仅是std :: string。也就是说,在Windows上更有可能需要std :: wstring - ildjarn
@ildjarn,你是不是想说 std::basic_string<TCHAR> - Mark Ransom
@MarkRansom:不,我的意思是整个std::basic_string<>类模板,而不是特定的std::basic_string<char>专业化(也称为std::string)。 - ildjarn
8
“Portable”与“MFC”相结合是个自相矛盾的说法。 - John Dibling

3
请勿使用CString。它使用COW实现,非常容易受到线程等问题的影响。请勿使用char *或LPCTSTR(只是const char *或const wchar_t *换个名字),因为它们不管理自己的内存。在Windows上使用std::string处理8位代码点,使用std::wstring处理16位代码点(在Unix中使用32位)。请注意保留HTML标记。

6
并不是像std::string那样线程安全。但是因为使用MFC时,通常使用CString。-1。 - John Dibling
5
@John Dibling:std::string 在某种程度上是线程安全的,而 CString 则不是。如果你有两个独立的 std::string,你可以确保它们在两个线程上使用是安全的。但 CString 不具备这样的保证。 - Puppy
2
@ChristianRau:问题只在C++11标准中官方地得到了修复,但是这个问题在五年前的缺陷报告530中已经被正式确认,并且自那时以来已经在每个主要的标准库实现中实施(如果不是更早)。 - ildjarn
2
@DeadMG:有没有一篇文章或者Stack Overflow的问题链接说明了两个CString实例不能在不同的线程中独立使用?如果真是这样,听起来相当严重。这是某种特殊情况还是普遍情况?我将使用VS 6.0。是否有更新的VS版本可以解决这个问题? - Bob Bryan
2
线程规则已经明确说明。如果这还不够好,可以实现自定义同步,或使用不同的字符串类。对于MFC代码,最好使用CString。特别是如果你也在使用COM。我还假设所有出现的“codepoints”都应该读作“code units”。也许你至少可以修复一下这个问题。 - IInspectable
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接