Смешивание стандартных строк c ++ и API Windows - PullRequest
3 голосов
/ 13 марта 2010

Многие оконные API-интерфейсы получают указатель на буфер и элемент размера, но результат должен идти в строку c ++. (Я использую Windows Unicode, поэтому они wstrings)

Вот пример: -

#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, это просто удобный пример.

Ответы [ 4 ]

7 голосов
/ 13 марта 2010

В этом случае я не вижу, что std :: vector приносит на вечеринку. MAX_COMPUTERNAME_LENGTH вряд ли будет очень большим, поэтому я бы просто использовал массив в стиле C в качестве временного буфера.

3 голосов
/ 13 марта 2010

См. этот ответ на другой вопрос. Он предоставляет источник для класса StringBuffer, который очень аккуратно обрабатывает эту ситуацию.

2 голосов
/ 13 марта 2010

Я бы сказал, поскольку у вас уже есть задача абстрагировать Windows API за более общий интерфейс C ++, полностью отказаться от вектора и не беспокоиться о конструкторе wstring:

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

    GetComputerNameW(name, &size);

    return name;
}

Эта функция вернет действительный объект wstring.

1 голос
/ 13 марта 2010

Я бы использовал вектор. В ответ на ваше заявление о том, что вы выбрали плохой пример, на мгновение представьте, что у нас нет разумной постоянной верхней границы длины строки. Тогда это не так просто:

#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::reference равно wchar_t&, то вы отсортированы. 21.3.4 определяет, что неконстантный operator[] возвращает reference и что он возвращает data()[pos]. Так что, если reference является простым wchar_t&, тогда нет возможности для захватывающего поведения копирования при записи через ссылку, и строка должна фактически быть модифицируемой через указатель &buffer[0]. Я думаю. Основная проблема здесь заключается в том, что стандарт допускает реализации более гибкие, чем оказалось необходимо.

Хотя это много усилий и комментариев, просто чтобы избежать копирования строки, поэтому я никогда не чувствовал необходимости избегать промежуточного массива / вектора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...