在C++中,通过引用和通过值将向量传递到函数中
Passing vectors into function by reference vs by value in C++
我一直在写一个小项目,只是为了扩展我对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 }
然而,如果我的函数verify采用了一个向量&b它很好用。有人能解释为什么会发生这种情况吗?
用户.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 messagesn" : "User has 1 messagen");
43
44 }
除了关于使用std::string
的所有讨论之外,OP代码中的基本问题是缺少用户定义的User
类的复制构造函数。默认的将只复制userName
和passWord
字段中的值,导致两个矢量(main
中的矢量和为verify
函数创建的矢量)指向相同的分配内存地址。当verify
返回时,该内存被删除,使main
中向量中的Users
具有悬空指针(指向释放的内存)。
使用引用可以避免这种删除,并保持原始向量不变。
这就是为什么现在不应该在代码中使用原始指针的原因之一。
我强烈建议尽可能使用C++功能而不是C语言,因为它通常更可读,不易出错。
现在你的代码中有多个问题,@AlanStrokes的评论是对的,你的主要问题是没有正确处理三规则。
User
类进行动态分配,但不定义复制构造函数和赋值运算符。对于显示问题的简单片段,请查看此处的片段。它只复制地址,而不是指向的实际数据,所以一旦第一个副本被删除,所有其他副本都无效。
您还有其他问题,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++自动处理所有的复制和删除逻辑,您不必处理烦人的指针内容。
在我做了最小的更改之后,它看起来工作得很好,所以它实际上是编译的。我只是使用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;
}
当我在ideone上运行这个程序,输入"foo"三次,然后输入"Greg"时,它会在每个"foo"之后不断提示,然后接受"Greg"。
由于用另一个类代替看不见的"User"类可以使其工作,所以问题一定出在该类中,可能是在处理传递给其构造函数的指针时。
一些注意事项:
不需要将字符串文字"foo"answers"bar"强制转换为
(char*)
;它们已经是CCD_ 21。如果你这样做是为了摆脱const
-ness,不要这样做:它们可能存在于只读内存中。如果您有C++11,
verify
中的循环可以替换为的范围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; })
,如果username
已经在向量users
中,则返回true
。
因此,一个更短、等效的完整程序是
#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;
}
(在视频上)
- 函数向量_指针有不同的原型,我可以构建一个吗
- 如何使用向量的template_back函数
- 如何删除除 ArduinoSTL 的向量函数之外的所有函数
- 在使用标准向量函数时引发'std::bad_alloc'实例后调用的终止
- 我可以为向量函数返回 NULL<double> 吗?
- 将多个向量(函数结果)组合到一个使用模板中
- 如何在 c++ 中制作通用字符串到向量函数
- 为什么简单的C++向量函数会产生越界的下标
- 为什么我的向量函数的返回值总是 1
- 模板化向量函数参数的std::is_base_of
- 我的程序没有运行,多维向量函数
- C 如何使2D向量函数
- 如何从 v8 返回向量<T> C++ 函数
- C++ 如何使此向量函数接受任何分隔符
- 我想返回一个向量函数,<Competition>但被告知竞争是未声明的,并且我正在使用未定义的类'std::vector'
- C++:如何在类中使用向量函数
- 自己的"Insert"方法(向量)函数模板
- c++中的内存泄漏:循环中的向量函数
- 如何添加一个元素到一个向量函数
- 向量函数'at'