为什么没有std :: for_each + lambda按预期工作?

时间:2014-01-10 10:27:43

标签: c++ c++11 stl lambda operator-overloading

这是 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

2 个答案:

答案 0 :(得分:3)

可能是因为elements指向char的数组,所以每个元素都是char,而不是char*

您还需要将&放在s.elementss.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)

{p> sizeof(pointer)其中pointerchar const*,不返回数组的长度。你犯了多次这个错误。请改用strlen。这是隐藏的,因为你的字符串是4个字符长,而32位系统sizeof(ptr)是4。

&first_free中的下一个for_each和类似内容应为first_free

接下来,你的lambda应该char而不是char*。然后输出应该是<< p而不是<< *p

您应该同时创建const和非const beginendconst返回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 }