2010-03-13 72 views
3

许多windows APIs都会获取指向缓​​冲区和大小元素的指针,但结果需要放入C++字符串中。 (我在这里使用的是Windows的Unicode所以他们wstrings)混合C++标准字符串和窗口API

下面是一个例子: -

#include <iostream> 
#include <string> 
#include <vector> 
#include <windows.h> 

using namespace std; 

// This is the method I'm interested in improving ... 
wstring getComputerName() 
{ 
    vector<wchar_t> buffer; 
    buffer.resize(MAX_COMPUTERNAME_LENGTH+1); 
    DWORD size = MAX_COMPUTERNAME_LENGTH; 

    GetComputerNameW(&buffer[0], &size); 

    return wstring(&buffer[0], size); 
} 

int main() 
{ 
    wcout << getComputerName() << "\n"; 
} 

我真正的问题是,这是写getComputerName功能,使得它适合的最佳方式C++更好,还是有更好的方法?我没有看到任何方式直接使用字符串,没有通过矢量直接使用,除非我错过了什么?它工作正常,但不知何故似乎有点难看。问题不在于特定的API,而仅仅是一个简单的例子。

回答

7

在这种情况下,我看不到什么std :: vector带给聚会。 MAX_COMPUTERNAME_LENGTH不可能非常大,所以我只是简单地使用一个C风格的数组作为临时缓冲区。

+0

好吧,我的例子是一个糟糕的,我用了一个载体,因为我可能直到运行时才知道我想要缓冲区有多大。我完全同意这个例子没有必要 – jcoder 2010-03-13 10:16:16

+0

@JB嗯,我不认为有任何一般规则 - 你必须以你自己的方式处理你使用的每个API。这部分是因为整个API背后并没有一个完整的设计理念。 – 2010-03-13 10:23:45

+0

好的,谢谢,真的,我只是想检查我不会错过任何明显的更好的方法来实现这个 – jcoder 2010-03-13 10:25:39

2

我会说,既然你已经在抽象的Windows API更通用的C++接口后面的任务,破除矢量干脆,不要理会wstring的构造函数:

wstring getComputerName() 
{ 
    wchar_t name[MAX_COMPUTERNAME_LENGTH + 1]; 
    DWORD size = MAX_COMPUTERNAME_LENGTH; 

    GetComputerNameW(name, &size); 

    return name; 
} 

此功能将返回一个有效的wstring对象。

+0

getComputerName()应该返回一个LPCWSTR(const wchar_t *)并让调用者根据需要构造一个wstring,可以是静态的。 – 2010-03-13 12:43:27

+0

我以为OP想要抽象Windows API,而是使用一致的C++接口,在这种情况下,我相信返回一个C++字符串(可能是const)是要走的路,而不是更多的“const wchar_t *”。还是你完全提到了其他的东西? – amn 2010-03-13 12:50:02

+0

我认为Alain的观点是,在返回时自动转换没有太大好处 - 调用者可以编写'wstring n = getComputerName();'或'wstring n; n = getComputerName();'不管返回类型是'wstring'还是'wchar_t *'。所以他说的是做最大的灵活性的事情。在这种情况下,我不太喜欢他的“静态”缓冲区,但我不认为这种改变是值得使该函数非线程安全的,因为YAGN wchar_t *返回。所以在这种情况下,我认为这是值得转换的功能。 – 2010-03-13 12:56:21

3

请参阅this answer另一个问题。它提供了一个StringBuffer类来处理这种情况非常干净。

1

我会使用该向量。为了回应你说你选择了一个不好的例子,假装我们没有合理的字符串长度上限。然后它不是那么容易:

#include <string> 
#include <vector> 
#include <windows.h> 

using std::wstring; 
using std::vector; 

wstring getComputerName() 
{ 
    DWORD size = 1; // or a bigger number if you like 
    vector<wchar_t> buffer(size); 
    while ((GetComputerNameW(&buffer[0], &size) == 0)) 
    { 
     if (GetLastError() != ERROR_BUFFER_OVERFLOW) aargh(); // handle error 
     buffer.resize(++size); 
    }; 
    return wstring(&buffer[0], size); 
} 

在实践中,你可能会写入字符串,但我不完全确定。除了标准中的内容之外,您当然需要通过实施std::wstring所做的额外保证,但我希望MSVC的字符串可能是正确的。

我认为,如果wstring::referencewchar_t&那么你是排序。 21.3.4定义非const operator[]返回reference,并返回data()[pos]。因此,如果reference只是一个普通的wchar_t&,那么通过该引用没有激发写时复制行为的范围,并且该字符串实际上可以通过指针&buffer[0]修改。我认为。这里的基本问题是标准允许实现更多的灵活性而不是需要的。

尽管为了避免复制一个字符串而做了大量的工作和评论,所以我从来没有觉得需要避免中间数组/矢量。

+0

嗯,是的,我想这不假设有关wstring的假设,但由于这段代码本质上依赖于平台,无论如何,这不是一个问题, – jcoder 2010-03-13 14:03:17

+0

嗯,GetComputerNameW只要求你在Windows上,而'wstring'的必要条件可以想像由一些Windows编译器/库实现满足,但不是其他。所以做出假设确实会使代码更“依赖”平台。就是说,它适用于使用向量处理的实现的子集,子集可能是严格的,即使它不严格,每个实现需要额外的工作才能证明它不是。为了说明这一点,我的计算机名称全部为5个字符;-) – 2010-03-13 14:32:17