Как получить адрес станд.:: векторный буферный запуск наиболее изящно?

Я всегда использую DisplayName, Description и DefaultValue атрибуты по общественным собственностям моих пользовательских элементов управления, пользовательских элементов управления или любого класса, который я отредактирую через сетку свойства. Эти теги используются.NET PropertyGrid для форматирования имени, панели описания и значений bolds, которые не установлены к значениям по умолчанию.

[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
    ...
} 

я просто желаю, чтобы IntelliSense Visual Studio принял бы во внимание эти Description атрибут, если никакой XML-комментарий не найден. Это избежало бы необходимости повторять то же предложение дважды.

12
задан Martin B 27 August 2009 в 07:52
поделиться

10 ответов

Well, you can remove one set of parens:

&buffer[0]

but that is the common, idiomatic way of doing it. If it really offends you, I suppose you could use a template - something like:

template <typename T> 
T * StartOf( std::vector <T> & v ) {
    return &v[0];
}
20
ответ дан 2 December 2019 в 02:49
поделиться

Actually, the main problem with &buffer[0] (note the absence of parantheses) isn't that it isn't really pretty. (That's subjective anyway. I remember finding buffer.begin(), buffer.end() not pretty at all, when I first learned to use the STL.)

The main problem is that it invokes undefined behavior whenever buffer is empty -- and most code never checks for that. That's why I put these into my toolbox:

template <class T, class TAl>
inline T* begin_ptr(std::vector<T,TAl>& v)
{return  v.empty() ? NULL : &v[0];}

template <class T, class TAl>
inline const T* begin_ptr(const std::vector<T,TAl>& v)
{return  v.empty() ? NULL : &v[0];}

template <class T, class TAl>
inline T* end_ptr(std::vector<T,TAl>& v)
{return v.empty() ? NULL : (begin_ptr(v) + v.size());} 

template <class T, class TAl>
inline const T* end_ptr(const std::vector<T,TAl>& v)
{return v.empty() ? NULL : (begin_ptr(v) + v.size());}

Using these, you can write your code as

callFunction( begin_ptr(buffer), buffer.size() );

Whether begin_ptr(buffer) is prettier than &buffer[0] is left for you to decide. However, given that NULL should be checked for every pointer function argument, it definitely is more safe.

19
ответ дан 2 December 2019 в 02:49
поделиться

but this &(buffer[0]) looks ugly

It’s the normal way. You can omit the parentheses, though:

&buffer[0]
12
ответ дан 2 December 2019 в 02:49
поделиться

No.

7
ответ дан 2 December 2019 в 02:49
поделиться

Try &(buffer.front()), but it's not much prettier :)

4
ответ дан 2 December 2019 в 02:49
поделиться

Elegant way would be to change callFunction or to write wrapper for it as follows:

// legacy function
void callFunction( TCHAR* buf, int buf_size)
{
  // some code
}

// helpful template
void callFunction( std::vector<TCHAR>::iterator begin_it, std::vector<TCHAR>::iterator end_it )
{
  callFunction( &*begin_it, std::distance( begin_it, end_it ) );
}

// somewhere in the code
int neededLength = computeLength();
std::vector<TCHAR> buffer( neededLength );
callFunction( buffer.begin(), buffer.end() );

You could even make wrapper for all such functions (with different types, not only TCHAR):

template<typename T>
void callFunction( T begin_it, typename std::vector<typename T::value_type>::iterator end_it )
{
  callFunction( &*begin_it, std::distance( begin_it, end_it ) );
}

Type T will be properly deduced (as std::vector) and you'll be able still write callFunction( buffer.begin(), buffer.end() );.

Note that you cannot declare template function as void callFunction( typename std::vector::iterator begin_it, typename std::vector::iterator end_it ) as someone proposed recently as an edit to this answer, because in that case you will get the deducion error.

3
ответ дан 2 December 2019 в 02:49
поделиться

Причина, по которой это выглядит некрасиво, в том, что вы находитесь на границе красивого и чистого кода в стиле C ++ и красивого и чистого кода в стиле C. В коде C ++ используются итераторы, в коде C используются указатели и размеры.

Вы можете создать клей, чтобы обойти эти проблемы:

template< typename at_Container, typename at_Function >
void for_container( at_Container& c, at_Function f ) {
    f( &c[0], c.size() );
}

и вызвать его в клиентском коде.

void afunction( int* p, size_t n ) { 
   for( int* p = ap; p != ap+n; ++p ) {
     printf( "%d ", *p );
   }
}

void clientcode() {
   std::vector<int> ints(30,3);
   for_container( ints, afunction );
}
2
ответ дан 2 December 2019 в 02:49
поделиться

Для таких функций я использую служебный класс SizedPtr , который в основном содержит указатель и количество элементов. Набор функций преобразователя создает SizedPtr из разных входов. Таким образом, вызов меняется на:

vector<TCHAR> foo;
callFunction(sizedptr(foo));

Можно даже добавить неявный конструктор std :: vector в SizedPtr , но я хотел избежать этой зависимости.

Это помогает, только если callFunction находится под вашим контролем. С ним приятно работать, если вы работаете с разными типами векторов в одном приложении и хотите их объединить. Если вы обычно работаете с std :: vector , в большинстве случаев это бессмысленно.

Примерно:

template<typename T>
class SizedPtr
{
    T * m_ptr;
    size_t m_size;
  public:
    SizedPtr(T* p, size_t size) : ... {}
    T * ptr() { return m_ptr; }
    size_t size() const { return m_size; }

   // index access, STL container interface, Sub-Sequence, ...

}

Идея состоит в том, чтобы отделить операцию - управление непрерывной последовательностью элементов - от хранилища (std :: vector). Это похоже на то, что STL делает с итераторами, но позволяет избежать заражения шаблонов.

2
ответ дан 2 December 2019 в 02:49
поделиться

As already said, no.

The reason is that &buffer[0] is the only way guarantied by the standard to get the adresse of the vector buffer.

1
ответ дан 2 December 2019 в 02:49
поделиться

Если вы используете std :: vector только для его свойств RAII (чтобы он освободил для вас память), и вам на самом деле не нужно изменять размер или что-то в этом роде, вы можете лучше использовать Boost scoped_array

boost::scoped_array<TCHAR> buffer( new TCHAR[neededLength] );
callFunction( buffer.get(), neededLength );

scoped_array вызовет delete [] для массива, когда он выйдет за пределы области видимости.

1
ответ дан 2 December 2019 в 02:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: