通过引用将向量传递给函数与使用C ++中的值传递

时间:2016-05-28 21:57:44

标签: c++ vector reference

我一直在写一个小项目,只是为了扩展我对c ++的了解,我遇到了一个问题。当我接受用户名时,我想检查是否已经使用了。如果获得该特定用户名,我会将问题重新打印给用户。它在第一个循环中运行良好,但在此之后它将接受任何内容,即使它确实存在于用户Vector中。

     bool verify(char * a, vector<User> b){
 14         for(int i = 0; i < b.size(); i++){
 15                 if(strcmp(a, b[i].getUsername()) == 0){
 16                         return false;
 17                 }
 18         }
 19         return true;
 20 }
 21 
 22 int main(){
 23 
 24         vector<User> users;
 25 
 26         User us1((char *)"foo", (char *)"bar");
 27         users.push_back(us1);
 28 
 29         
 30         do{
 31                 cout << "Enter Username: ";
 32                 scanf(" %s", username);
 33                 
 34                 
 35         } while(!verify(username, users));
 36         
 37         return 0;
 38 }   

然而,如果我的功能验证反而采用了矢量&amp; b它工作正常。有人可以解释为什么会这样吗?

User.cpp

    User:: User(char * userName, char * passWord){
  9 
 10         this->userName = strdup(userName);
 11         this->passWord = strdup(passWord);
 12 
 13 }
 14 
 15 User:: ~User(){
 16 
 17         delete userName;
 18         delete passWord;
 19 
 20 }
 21 
 22 void User::getMessage(){
 23 
 24         cout << message << endl;
 25 }
 26 
 27 char * User:: getUsername(){
 28 
 29         return userName;
 30 }
 31 
 32 char * User :: getPassword(){
 33 
 34         return passWord;
 35 }
 36 
 37 void User:: printUser(){
 38 
 39         cout << "User Information" << endl;
 40         cout << "Username: "<< userName << endl;
 41         cout << "Password: "<< passWord << endl;
 42         cout << "Messages: "<< ((message == NULL) ? "User has no messages\n" : "User has 1 message\n");
 43 
 44 }

3 个答案:

答案 0 :(得分:2)

除了使用std::string之外的所有讨论,OP代码中的基本问题是缺少User类的用户定义的复制构造函数。默认值只会复制userNamepassWord字段中的值,导致两个向量(main中的一个和为verify函数创建的一个)指向到相同的分配内存地址。当verify返回时,该内存将被删除,将Users保留在main中的向量中,悬挂指针(指向已释放的内存)。

使用该引用可避免此删除并保持原始矢量不变。

这就是为什么你现在不应该在代码中使用原始指针的原因之一。

答案 1 :(得分:0)

我强烈建议尽可能使用C ++功能而不是C语言,它通常更具可读性且不易出错。

现在代码中存在多个问题,而@AlanStrokes' comment是正确的,你的主要问题是没有正确处理三条规则。

您的User类执行动态分配,但未定义copyconstructor和赋值运算符。有关显示问题的简单代码段,请查看代码段here。它只复制地址,而不是指向的实际数据,因此一旦第一个副本被删除,其他所有数据都无效。

您还有其他问题,strdup是不可移植的,它不是C标准的一部分。它是POSIX标准的一部分,因此很可能仅在实现该标准的系统上可用。它也是一个用malloc分配内存的C函数,你应该删除它从C返回free的指针,而不是C ++中的delete

还有一个原因是C ++中的字符串文字是const char[],事实上在C中它们是char[]但是你不允许编辑它们所以它实际上也是常量。那是因为允许编译器将字符串文字放入可执行文件的只读位置。因此,不要将字符串文字投射到char *,而是使您的函数正确地使用const char *

所有这些说处理那些指针的东西都很烦人,因为C ++使std::string变得更容易,我推荐使用它:

class User {
  private:
    std::string userName;
    std::string password;

    User(const std::string &userName, const std::string & passWord);
    std::string getUsername();
    std::string getPassword();
    void printUser();
};

User::User(const std::string & userName, const std::string & passWord) {
  this->userName = userName;
  this->passWord = passWord;
}

std::string User::getUsername() {
  return userName;
}

std::string User::getPassword() {
  return passWord;
}

// etc...

这里C ++自动处理所有复制和删除逻辑,你不必处理讨厌的指针。

答案 2 :(得分:0)

它做得很好,在我做了最小的改动之后它实际编译了。 我只是使用std :: string存储字符串而不是猜测你的User类。

#include <vector>
#include <string>
#include <iostream>
#include <cstdio>
#include <cstring>

struct User {
    std::string name, game;
    User(const char* nam, const char* gam) : name(nam), game(gam) {}
    const char* getUsername() const {
        return name.c_str();
    }
};

bool verify(char * a, std::vector<User> b) {
    for (int i = 0; i < b.size(); i++) {
        if (std::strcmp(a, b[i].getUsername()) == 0) {
            return false;
        }
    }
    return true;
}

int main(){    
    std::vector<User> users;

    User us1("foo", "bar");
    users.push_back(us1);

    char username[100];

    do {
        std::cout << "Enter Username: ";
        std::scanf(" %50s", username);
    } while(!verify(username, users));

    return 0;
}

当我运行此on ideone,输入“foo”三次然后输入“Greg”时,它会在每个“foo”之后继续提示,然后接受“Greg”。

由于将另一个类替换为您看不见的“User”类使其工作,问题必须在该类中,可能在您处理传递给其构造函数的指针时。

一些注意事项:

  • 不需要将字符串文字“foo”和“bar”强制转换为(char*);他们已经char*了。如果您这样做是为了摆脱const - ness,请不要:它们可能位于只读内存中。

  • 如果你有C ++ 11,verify中的循环可以替换为range-for:

    for (auto u : b) {
        if (strcmp(a, u.getUsername()) == 0)
            return false;
    }
    
  • 实际上,您可以删除整个函数verify并使用std::any_of(users.begin(), users.end(), [username](const User& u){ return strcmp(u.getUsername(), username) == 0; }),如果true已经在向量username中,则返回users }。

所以一个较短的,等效的完整程序

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

struct User {
    std::string name, game;
    User(const char* nam, const char* gam) : name(nam), game(gam) {}
    const std::string& getUsername() const {
        return name;
    }
};

int main(){
    std::vector<User> users;
    users.push_back({"foo","bar"});
    std::string username;

    do {
        std::cout << "Enter Username: ";
        std::cin >> username;
    } while(std::any_of(users.begin(), users.end(),
            [username](const auto& u){ return u.getUsername() == username; }));

    return 0;
}

on ideone