这是 C ++ Primer 5th Edition 的练习:
练习14.7:为你 String 类定义一个输出运算符 为第13.5节(第531页)中的练习写作。(第558页)
我为之前的练习写的string.h
:
/**
* @brief std::string like class without template
*
* design:
*
* [0][1][2][3][unconstructed chars][unallocated memory]
* ^ ^ ^
* elements first_free cap
*/
class String
{
friend std::ostream& operator <<(std::ostream& os, const String& s);
public:
//! default constructor
String();
//! constructor taking C-style string i.e. a char array terminated with'\0'.
explicit String(const char * const c);
//! copy constructor
explicit String(const String& s);
//! move constructor --07.Jan.2014
String(String&& s) noexcept;
//! operator =
String& operator = (const String& rhs);
//! move operator = --07.Jan.2014
String& operator = (String&& rhs) noexcept;
//! destructor
~String();
//! members
char* begin() const { return elements; }
char* end() const { return first_free; }
std::size_t size() const {return first_free - elements; }
std::size_t capacity() const {return cap - elements; }
private:
//! data members
char* elements;
char* first_free;
char* cap;
std::allocator<char> alloc;
//! utillities for big 3
void free();
};
std::ostream&
operator << (std::ostream& os, const String& s);
string.cpp
的一部分:
//! constructor taking C-style string i.e. a char array terminated with'\0'.
String::String(const char * const c)
{
auto p = c;
char* newData = alloc.allocate(sizeof(p));
std::uninitialized_copy(p, (p + sizeof(p)), newData);
//! build the data structure
elements = newData;
cap = first_free = newData + sizeof(c);
}
std::ostream &operator <<(std::ostream &os, const String &s)
{
std::for_each(&s.elements, &s.first_free, [&](const char* p){
os << *p;
});
return os;
}
main.cpp
:
#include "string.h"
#include <iostream>
int main()
{
String s("1234");
std::cout << s <<"\n";
return 0;
}
输出:
1
Press <RETURN> to close this window...
为什么输出如此?为什么不1234
?
答案 0 :(得分:3)
可能是因为elements
指向char
的数组,所以每个元素都是char
,而不是char*
。
您还需要将&
放在s.elements
和s.first_free
之前,因为您对指针指向的地址感兴趣,而不是指针本身的地址。
所以,这段代码可行:
std::for_each(s.elements, s.first_free, [&](char p){
os << p;
});
正如@TemplateRex在评论中所提到的,使用begin()
和end()
成员函数会更清晰,更惯用:
std::for_each(s.begin(), s.end(), [&](char p){ os << p; });
答案 1 :(得分:1)
sizeof(pointer)
其中pointer
是char const*
,不返回数组的长度。你犯了多次这个错误。请改用strlen
。这是隐藏的,因为你的字符串是4个字符长,而32位系统sizeof(ptr)
是4。
&first_free
中的下一个for_each
和类似内容应为first_free
。
接下来,你的lambda应该char
而不是char*
。然后输出应该是<< p
而不是<< *p
。
您应该同时创建const
和非const
begin
和end
。 const
返回char const *
,而非const
返回char*
- 逻辑上拥有其基础数据的容器应使用const
这种方式进行迭代。
接下来将for_eaxh
替换为使用begin()
,将end()
替换为for_each( x.begin(), x.end(),
... - 无需重做begin
和{{1} }做。在C ++ 11中,您甚至可以使用基于范围的end
:
for
而不是for(char c : s ) {
std::cout << c
}
。