简体   繁体   English

std::size_t 与 size_type 作为参数和 function 返回类型

[英]std::size_t vs. size_type as parameters and function return types

Suppose I have this code.假设我有这个代码。 Which method is better?哪种方法更好?

// Method 1
std::size_t size()
{
  // m_myVector is of type std::vector<MyClass*> in all examples
  return m_myVector.size();
}

// Method 2
std::vector<MyClass*>::size_type size()
{
  // m_myVector is of type std::vector<MyClass*> in all examples
  return m_myVector.size();
}

The first way works in 99% of cases, but of course there's the off-chance that the size of the vector isn't of type std::size_t .第一种方法适用于 99% 的情况,但当然也有可能向量的大小不是std::size_t类型。 That said, we can just rely on a software analysis tool to tell us that the return type of the size of the vector has changed.也就是说,我们可以只依靠软件分析工具告诉我们向量大小的返回类型发生了变化。

The second way exposes implementation detail of the vector to the caller.第二种方式将向量的实现细节暴露给调用者。 Does this break encapsulation?这会破坏封装吗? I don't know, you tell me!我不知道,你告诉我!

Here's another more complex example.这是另一个更复杂的例子。 Which method is better?哪种方法更好?

void doFoo(const SomeClass& someObject)
{
  // These could be ints or size_types... Feel free to use your imagination
  std::size_t firstCount = someObject.getFirstCount();
  for (std::size_t i = 0U; i < firstCount; ++i)
  {
    foo(firstCount);
  }
}

void doFoo2(const SomeClass& someObject)
{
  // I thought I'd provide another example to help your imagination :)
  std::vector<MyClass*>::size_type secondCount = someObject.getSecondCount();
  for (std::vector<MyClass*>::size_type i = 0U; i < secondCount; ++i)
  {
    foo(secondCount);
  }
}

void doFoo3(const SomeClass& someObject)
{
  // The correct styling would be: NotMyClass*
  // But I really wanted to emphasize this was different from above, so I ALL CAPPED IT
  std::vector<NOTMYCLASS*>::size_type thirdCount = someObject.getThirdCount();
  for (std::vector<NOTMYCLASS*>::size_type i = 0U; i < thirdCount; ++i)
  {
    foo(thirdCount);
  }
}

// Method 1
void foo(std::size_t index)
{
  // m_myVector is of type std::vector<MyClass*> in all examples
  m_myVector.at(index)->doLotsOfStuff();
}

// Method 2
void foo(std::vector<MyClass*>::size_type index)
{
  // m_myVector is of type std::vector<MyClass*> in all examples
  m_myVector.at(index)->doLotsOfStuff();
}

Okay this is a lengthy example so I'll explain what's going on.好的,这是一个很长的例子,所以我将解释发生了什么。 doFoo() , doFoo2() , and doFoo3() all call foo() which takes in a std::size_t in the first implementation or std::vector<MyClass*>::size_type in the second implementation. doFoo()doFoo2()doFoo3()都调用foo() ,它在第一个实现中接收std::size_t或在第二个实现中接收std::vector<MyClass*>::size_type

doFoo() is passing in a std::size_t to foo() , so the first implementation of foo() makes more sense here but then we index a std::vector<MyClass*> which is expecting a std::vector<MyClass*>::size_type . doFoo()std::size_t传递给foo() ,所以foo() () 的第一个实现在这里更有意义,但是我们索引一个std::vector<MyClass*> ,它期待一个std::vector<MyClass*>::size_type Not particularly great if size_type was not defined to be std::size_t .如果size_type未定义为std::size_t ,则不是特别好。

doFoo2() is passing in a std::vector<MyClass*>::size_type to foo() , so the second implementation of foo() works very nicely here. doFoo2()std::vector<MyClass*>::size_type传递给foo() ,因此foo() () 的第二个实现在这里工作得很好。 No gripes other than exposing the implementation details of the private vector to the caller.除了将私有向量的实现细节暴露给调用者之外,没有其他抱怨。 And finally I'd imagine that we would need to include a separate header for MyClass .最后我想我们需要MyClass包含一个单独的 header

doFoo3() is passing in a std::vector<NOTMYCLASS*>::size_type to foo() ... And neither implementation of foo() expects this because the only vector that foo() cares about is the vector which holds elements of type MyClass* . doFoo3()正在将std::vector<NOTMYCLASS*>::size_type传递给foo() ...而且foo()的实现都没有期望这一点,因为foo()关心的唯一向量是包含元素的向量MyClass*类型。 Now, as an academic question, is std::vector<NOTMYCLASS*>::size_type always the same as std::vector<MyClass*>::size_type ?现在,作为一个学术问题, std::vector<NOTMYCLASS*>::size_type总是与std::vector<MyClass*>::size_type相同? I actually don't know the answer to this one, but I've been hearing 'yes' and 'no' .我实际上不知道这个问题的答案,但我一直听到“是”和“不是” And finally, there's that issue of encapsulation once again (if it is an issue).最后,再次出现封装问题(如果这是一个问题)。

Anyways, thanks for bearing with me.不管怎样,谢谢你对我的包容。 Thoughts?想法?

but of course there's the off-chance that the size of the vector isn't of type std::size_t但是当然有可能向量的大小不是 std::size_t 类型

Such off-chance doesn't practically exist in this case because std::vector<MyClass*>::size_type is (indirectly guaranteed and required to be) of type std::size_t .在这种情况下,这种机会实际上并不存在,因为std::vector<MyClass*>::size_type是(间接保证并且必须是)类型std::size_t Using std::size_t is fine in this case, and it doesn't leak unnecessary implementation details.在这种情况下使用std::size_t很好,并且不会泄漏不必要的实现细节。


In the case of standard containers, Container::size_type is defined based directly on on what allocator is being used.在标准容器的情况下, Container::size_type直接基于正在使用的分配器定义。 Thus, using size_type is typically only necessary when the allocator type - or the container type itself - is templated.因此,通常只有在分配器类型或容器类型本身被模板化时才需要使用size_type In the allocator case, you can use allocator traits instead of the container member type which allows you to keep the container type hidden.在分配器的情况下,您可以使用分配器特征而不是容器成员类型,这允许您隐藏容器类型。 If the container type itself is templated, then there is no point in hiding it since only someone who knows the container could have instantiated the template in the first place.如果容器类型本身是模板化的,那么隐藏它是没有意义的,因为只有知道容器的人才能首先实例化模板。

Furthermore, you can hide - or rather obfuscate (in a positive, encapsulating way) - the function declaration by creating a type alias member, just like std::vector has a type alias member based on its allocator.此外,您可以通过创建类型别名成员来隐藏 - 或者更确切地说混淆(以积极的封装方式) - function 声明,就像std::vector具有基于其分配器的类型别名成员一样。

Example:例子:

template<class Alloc>
class Foo
{
    // could be hidden with PIMPL if desired
    std::vector<MyClass*, Alloc> m_myVector;

public:
    // Since C++11
    using size_type = typename std::allocator_traits<Alloc>::size_type;
    // Prior to C++11
    typedef typename Alloc::size_type size_type;
    
    size_type size();
};

std::size_t is a type capable of holding the size of any array, including arrays allocated through allocators. std::size_t是一种能够保存任何数组大小的类型,包括通过分配器分配的 arrays。

This means that std::size_t will always be able to store the result of std::vector<T>::size() , so method 1 will never lead to an overflow and is perfectly readable.这意味着std::size_t将始终能够存储std::vector<T>::size()的结果,因此方法 1 永远不会导致溢出并且完全可读。

There is no guarantee that std::vector<T>::size_type is the same for all T , but you would be hard-pressed to find an implementation of std::vector where size_type is not always std::size_t .不能保证std::vector<T>::size_type对于所有T都是相同的,但是您很难找到std::vector的实现,其中size_type并不总是std::size_t

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM