我正在从C指针过渡到C++指针,现在正在学习auto_ptr。这是我尝试过的程序:
#include <iostream>
#include <memory>
#include "Car.h"
using namespace std;
typedef auto_ptr<Car> CarPtr;
int main() {
CarPtr au_ptr1(new Car());
CarPtr au_ptr2 = new Car();
Car *norm_ptr1 = new Car();
Car *norm_ptr2(new Car());
int *i_ptr1=new int();
int *i_ptr2(new int());
}
像下面这样的陈述意味着什么?
int *i_ptr2(new int());
Car *norm_ptr2(new Car());
上面提到的语句编译成功。下面的一个,抛出编译错误-CarPtr au_ptr2 = new Car();
为什么?
提前感谢
它确实有一个复制构造函数,但转换构造函数是显式的,这就是导致错误的原因:
explicit auto_ptr (X* p=0) throw();
这意味着Car*
不能隐式转换为auto_ptr<Car>
,这就是
CarPtr au_ptr2 = new Car();
尝试执行。这被称为复制初始化,而不是:
CarPtr au_ptr1 (new Car());
这是值初始化。第一个版本将尝试从Car*
创建临时CarPtr
,并使用它来初始化au_ptr2
。第二个直接调用复制构造函数。
等报表
int *i_ptr2(new int());
简单地用括号中的值初始化指针。
通常对象有复制构造函数,指针不是对象,所以它们没有复制构造函数(或赋值运算符或析构函数)。更确切地说,指针依赖于默认的复制机制。
当您谈到auto_ptr
或任何其他智能指针时,它们只是指针的同名者。但实际上,它们是模板化对象,使用RAII机制。
CarPtr au_ptr2 = new Car(); // this is initialization not assignment
给出编译错误,因为对应的CarPtr::CarPtr(...)
构造函数被设置为explicit
,所以它不接受=
风格的初始化。
Raw指针没有构造函数,但在大多数情况下,它们可以像有构造函数一样使用。内置类型都可以从任何可转换为其类型的值初始化,就像具有复制构造函数的用户定义类一样。
int *i_ptr1=new int();
int *i_ptr2(new int());
意思是一样的。
我认为这基本上是因为模板:这意味着你可以像使用用户定义的类型一样使用类型T
,并编写T t(0);
、T(0)
或T()
,当T
恰好是内置类型时,其含义与T t = 0;
、(T)0
或(T)0
完全相同(再次)。实际上,无论T
有什么构造函数,T(0)
的含义都与(T)0
相同,但那些告诉你不要在C++代码中使用C风格转换的人试图忽略这一事实;-)
auto_ptr
实际上有一个复制构造函数,但与大多数复制构造函数不同,它采用了一个非常量参数,并修改了它的参数。这就是为什么在C++11中,它被弃用,而支持unique_ptr
,它没有复制构造函数,但有移动构造函数。
正如Luchian所说,CarPtr au_ptr2 = new Car();
的问题不仅在于复制构造函数,还在于缺乏从类型new Car();
、Car*
到auto_ptr<Car>
的隐式转换。复制初始化尝试将RHS隐式转换为LHS的类型,然后将其复制到LHS。这两种方法在本例中都失败了。直接初始化允许使用显式转换,并且不需要副本,因此它成功了。
内置类型的行为不像有构造函数一样的一种方式是默认初始化。你可以写:
int i = int();
并且保证CCD_ 28被初始化为零。因此,您可以想象它有一个无args构造函数将其设置为零。但是,如果int
真的是一个具有该构造函数的类类型,那么写:
int i;
也可以保证i
为零,但它不是(至少不在函数范围内)。
顺便说一句,不要对这一切太兴奋,也不要意外地调用所谓的"最麻烦的解析"。
int i();
相当于int i(void);
而不是int i(0);
。它声明了一个函数,而不是一个整数变量。