以下动作有什么错?
std::string * stringArray = new std::string[100];
delete stringArray;
每件事都看起来井然有序,你使用了new,搭配了delete,但是实际的情况是你的程序行为不明确,也就是说,stringArray所包含的100个string对象可能其中有99个不太可能会被适当删除,因为他们的析构函数可能根本没有调用。
我们需要知道,我们定义的那个指针指向的是单一的对象还是对象数组,对象数组的话我们要保证数组中每一个对象的析构函数都会被恰当的调用。
规则:
如果你在new表达式中使用 [ ],必须在相应的delete表达式中使用 [ ]。如果你在new表达式中不适用 [ ],在delete表达式中也不要使用[ ]。
尽量用 pass-by-reference-to-const 替换pass-by-value
本条款的要点:
1、尽量以pass-by-reference-to-const替换pass-by-value。前者更高效且可以避免切割问题。
2、这条规则并不适用于内建类型及STL中的迭代器和函数对象类型。对于它们,pass-by-value通常更合适。
这个在C++中是非常常见的,传值和传引用的巨大差别在于你使用的是参数本身还是其副本。缺省情况下C++是以by value传递的,其副本是对象本身的copy构造函数自动调用的,我们看下面的例子:
class Persion {
public:
Persion() {std::cout << "Persion()" << std::endl;}
virtual ~Persion(){std::cout << "~Persion()" << std::endl;}
private:
std::string name;
std::string address;
};
class Student :public Persion {
public:
Student() {std::cout << "Student()" << std::endl;}
//Student(const Student&cc){std::cout << "copy Student()" << std::endl;}
~Student(){std::cout << "~Student()" << std::endl;}
bool returntrue() {return true;}
private:
std::string schoolName;
std::string schoolAddress;
};
bool validateStudent(Student s)
{
return s.returntrue();
}
int main()
{
Student a; //调用Student,Persion构造函数
bool bb = validateStudent(a); //调用拷贝构造函数,函数运行完调用Student,Persion析构函数
system("pause");
return 0; //程序结束后销毁a,调用析构函数
}
运行结果如下:
其实除了这两个类中的构造函数和析构函数的调用,还有std::string中构造函数和析构函数的调用。一个小小的调用用了这么多的资源,这并不是我们的初衷,因此,我们应该避免创建新的对象。
bool returntrue() const
{
return true;
}
bool validateStudent(const Student &s)
{
return s.returntrue();
}
传递引用,为了不改变传进来对象的值,将其声明为const。
同时,这种by reference的形式还避免了对象切割(基类和派生类之间的关系),如下面代码所示:
class Window
{
public :
Window(){};
void name()const;
virtual void display()const;
};
void Window::name()const
{
cout<<"window name"<<endl;
}
void Window::display()const
{
cout<<" window display()"<<endl;
}
class WindowWithScrollBars:public Window{
public:
WindowWithScrollBars(){};
virtual void display() const;
};
void WindowWithScrollBars::display() const
{
cout<<"WindowWithScrollBars display()"<<endl;
}
void pintNaandWind(Window w)
{
w.name();
w.display();
}
int main()
{
WindowWithScrollBars wwsb;
pintNaandWind(wwsb);
return 0;
}
运行结果是:
因此,我们本想WindowWithScrollBars display() ,但是我们实际调用的确实Window display()。它调用的是window对象,而不是子类的。其实总体来看,就是这种传值的方式使得派生类对象强制转换成基类对象。因为他是by value,WindowWithScrollBars的所有特化信息都会被切除,这就是对象切割。那么解决办法就是 pass-by-reference-to-const。声明const是必要的,为了防止传入的对象被修改。
参考博文:
https://blog.youkuaiyun.com/wallwind/article/details/6845639
http://www.cnblogs.com/stemon/p/4577293.html
必须返回对象时,别妄想返回其reference。
但是并不是使用pass-by-reference-const就万无一失了,具体可以参考effective C++ 23.
结论:
绝不要返回pointer或者是reference指向一个local stack对象,或者返回reference指向一个heap-allocated对象,或者返回pointer或者是reference指向一个local static对象而有可能同时需要多个这样的对象。