无法使用pimpl惯用法将用户定义插入到封装的向量中

时间:2014-02-13 10:06:27

标签: c++ visual-c++ vector pimpl-idiom

我在TokenList类上使用Push函数时遇到了问题,我在其中封装了Tokens的向量。每当我调用Push函数时,即使我正确初始化Token变量,Token类中的成员变量字也是空的。我也试过使用整数并存储垃圾编号。

令牌类

class Token {
private:
    class Impl;
    std::unique_ptr<Impl> impl;
public:
    Token();
    Token(const Token& token);
    Token(const std::string& word);
    ~Token();
    std::string GetWord();
    void SetWord(const std::string& word);
};

TokenList类

class TokenList {
private:
    class Impl;
    std::unique_ptr<Impl> impl;
public:
    TokenList();
    TokenList(const TokenList& tokenList);
    ~TokenList();
    std::size_t Size() const;
    void Push(const Token& token);
    Token& operator[](int i);
    const Token& operator[](int i) const;
};

实施

class TokenList::Impl {
private:
    std::vector<Token> tokens;
public:
/* .... */
    void push(const Token& token) {
        tokens.push_back(token);
    }
};
void TokenList::Push(const Token& token) { impl->push(token); }

主要

TokenList tokens;
Token s1 ("hello");
Token s2 ("world");
tokens.Push(s1);
tokens.Push(s2);
for (int i = 0; i < tokens.Size(); ++i)
   cout << i << ": " << tokens[i].GetWord() << endl;

这是我运行main时的输出:

0:
1:

我尝试使用字符串而不是TokenList作为向量的类型参数,它完美地运行。当我跟踪问题时,在Push函数中没有获得正确传递的Token值。那么是什么原因导致TokenList的推送功能不采用令牌类的成员值?

1 个答案:

答案 0 :(得分:0)

我已经实现了所有丢失的代码,我无法重现您的问题。请注意,我添加了一个复制赋值运算符,因为对于存储在不可移动的向量中的类型,这是必需的。我已经发布了下面的代码,以便您可以与您的实现进行比较。 (这使用了一些C ++ 11特性)

#include <string>
#include <vector>
#include <iostream>
#include <memory>


class Token {
private:
    struct Impl;
    std::unique_ptr<Impl> impl;
public:
    Token();
    Token(const Token& token);
    Token(const std::string& word);
    Token& operator=(const Token& token);
    std::string GetWord();
    void SetWord(const std::string& word);
};

class TokenList {
private:
    struct Impl;
    std::unique_ptr<Impl> impl;
public:
    TokenList();
    TokenList(const TokenList& tokenList);
    std::size_t Size() const;
    void Push(const Token& token);
    Token& operator[](int i);
    const Token& operator[](int i) const;
};

// Token Implementation
struct Token::Impl
{
    std::string Word;
};

Token::Token() : impl{ std::make_unique<Impl>() }
{
}

Token::Token(const Token& token) : Token{}
{
    impl->Word = token.impl->Word;
}

Token::Token(const std::string& word) : Token{}
{
    impl->Word = word;
}

Token& Token::operator=(const Token& token)
{
    impl->Word = token.impl->Word;
    return *this;
}

std::string Token::GetWord()
{
    return impl->Word;
}

void Token::SetWord(const std::string& word)
{
    impl->Word = word;
}

// TokenList Implementation
struct TokenList::Impl 
{
    std::vector<Token> tokens;

    void push(const Token& token) 
    {
        tokens.push_back(token);
    }
};

TokenList::TokenList() : impl{ std::make_unique<Impl>() }
{
}

TokenList::TokenList(const TokenList& tokenList) : TokenList{}
{
    impl->tokens = tokenList.impl->tokens;
}

void TokenList::Push(const Token& token)
{ 
    impl->push(token); 
}

std::size_t TokenList::Size() const
{
    return impl->tokens.size();
}

Token& TokenList::operator[](int i)
{
    return impl->tokens[i];
}

const Token& TokenList::operator[](int i) const
{
    return impl->tokens[i];
}

int main()
{
    TokenList tokens;
    Token s1("hello");
    Token s2("world");
    tokens.Push(s1);
    tokens.Push(s2);
    for (int i = 0; i < tokens.Size(); ++i)
        std::cout << i << ": " << tokens[i].GetWord() << std::endl;

}