遇到的问题
这个文章用于记录在学习和使用C++的时候遇到的一些问题,以及解决方法,记载了一些非常零散的知识点,没有主题。
用new
申请结构体,并初始化结构体中的数组
在C++11
中,有一种新的方法在用new
运算符申请结构体内存的同时对其初始化。其格式为:
struct car{
int years;
double price;
};
car * p = new car{3, 23.5};
但是如果结构体中包含了字符数组(字符串),就不能使用这种格式,例如:
struct car{
char name [20];
double price;
};
car c {"Ford", 23.4}; //合法,在声明的时候可以用字符串的形式对数组进行初始化
car * p = new car {"Ford", 23.4};//非法,无法用该参数列表构造出car,不能将字符串转换成字符数组
car *c = new car{{'F','o','r','d'}, 23.4};//合法,用数组的形式传入参数,而不是字符串形式
造成这一错误的原因是因为,在new
调用car
的构造函数时,不能将字符串形式的参数转换成字符数组。
函数不能返回指向本地变量的指针
我们可以在函数中返回一个指针,但是该指针并不是可以指向任何它想指的地址。如果一不小心指向了被调用函数中的本地变量,等到函数返回之后,指针还是会指向函数中本地变量的地址,但是该地址已经被回收,等到下一次要使用栈的时候就会被分配出去,这时如果其他函数对该地址中的内容进行修改,就会发生数据混乱。例如:
int * inner(){
int * p, x = 1;
p = &x;
return p;
}
void another(){
int * p, x = 34;
p = &x;
}
int main(void){
int * p = inner();
printf("%d\n",*p);
another();
printf("%d\n",*p);
}
这里先调用inner()
并返回了一个指向其本地变量的指针。在函数执行完毕并返回之后,变量x
的内存被回收,但是并没有改变其中的内容(具体可以去看操作系统相关内容),并且指针还是指向了这一块内存,所以即使函数退出,变量销毁之后,还是能访问到该变量的值。
但是后面有调用了另一个函数another()
,该函数需要申请的内存跟inner()
完全一样,所以在inner()
对栈内存进行申请之后,inner()
中的x
跟another()
中的x
其实是同一个地址。在inner()
中修改了该地址中的内容之后,指针p
指向内存的内容也发生了改变。
函数返回本地变量
《C++ Primer Plus》上面说当函数返回一个本地对象作为返回值的时候,编译器将复制本地对象,再将其返回。但是我自己做实验的时候,情况却不是这样:
class Stock{
private:
double price;
public:
Stock(){
cout << "Using default constructor." << endl;
}
Stock(double);
Stock(const Stock &);
void show() const;
double getPrice() const;
};
Stock::Stock(double p){
price = p;
cout << "Initializing instance for " << price << endl;
}
Stock::Stock(const Stock & s){
cout << "Using copy constructor for " << s.price << endl;
}
void Stock::show() const{
cout << "Stock price is: " << price << endl;
}
double Stock::getPrice() const{
return price;
}
Stock sum(const Stock & s1, const Stock & s2){
Stock res(s1.getPrice() + s2.getPrice());
cout << "Instance address in function is: " << &res << endl; //打印本地变量的地址
return res;
}
Stock s1(2);
Stock s2(3);
Stock res = sum(s1, s2);
Stock cp = res;
cout << "Instance address outside function is: " << &res << endl; //打印调用函数范文内接收返回变量的地址
res.show();
上面的代码创建了两个Stock
类,并定义了一个函数将两个Stcok.price
,并且新建了一个本地对象用于存储相加后的值,返回值就是这个本地变量。但是程序运行之后,函数返回值的地址跟函数内本地对象的地址一样,并且函数返回的时候系统也没有调用Stock
类的复制构造函数。这可能是编译器对于函数返回对象这一行为做的内存优化。
如果函数返回的不是一个对象,而是一个原始类型,就不会出现上面的情况:
int test(){
int x = 3;
cout << "Address in the function is: " << &x << endl;
return x;
}
int x = test();
cout << "Address outside the function is: " << &x << endl;
在这个程序里,两个变量的地址不一样。