0

我正在从 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(); 为什么会这样?

提前致谢

4

3 回答 3

1

它确实有一个复制构造函数,但转换构造函数是显式的,这就是导致错误的原因:

explicit auto_ptr (X* p=0) throw();

这意味着 aCar*不能隐式转换为 a auto_ptr<Car>,这就是

CarPtr au_ptr2 = new Car();

尝试做。这称为复制初始化,而不是:

CarPtr au_ptr1 (new Car());

这是值初始化。第一个版本将尝试CarPtr从 a创建一个临时文件Car*并使用它来初始化au_ptr2. 第二个直接调用复制构造函数。

像这样的陈述

int *i_ptr2(new int());

只需使用括号中的值对指针进行值初始化。

于 2012-10-04T08:51:41.037 回答
0

原始指针没有构造函数,但在大多数情况下,它们可以像有构造函数一样使用。内置类型都可以从可转换为其类型的任何类型的值初始化,就像具有复制构造函数的用户定义类一样。

int *i_ptr1=new int();
int *i_ptr2(new int());

意思相同。

我认为这样做的原因基本上是模板:这意味着您可以像使用T用户定义的类型一样使用类型,并编写T t(0);or T(0)or T(),当T恰好是内置类型时,含义与T t = 0;(T)0(T)0(再次)。实际上,根据定义,无论构造函数具有什么含义,其含义都是相同的T(0),但是告诉您不要在 C++ 代码中使用 C 样式强制转换的人试图忽略这个事实 ;-)(T)0T

auto_ptr实际上确实有一个复制构造函数,但与大多数复制ctor不同,它需要一个非常量参数,并修改其参数。这就是为什么在 C++11 中它被弃用而支持unique_ptr,它没有复制构造函数,但有一个移动构造函数。

正如 Luchian 所说,问题CarPtr au_ptr2 = new Car();不在于(只是)复制构造函数,还在于缺少从new Car();, Car*, 到的类型的隐式转换auto_ptr<Car>。复制初始化尝试将 RHS 隐式转换为 LHS 的类型,然后将其复制到 LHS。在这个例子中,这两个都失败了。直接初始化允许使用显式转换,不需要副本,所以成功。

内置类型不像具有构造函数那样表现的一种方式是默认初始化。你可以写:

int i = int();

i保证初始化为零。所以你可能会想象它有一个无参数的构造函数将它设置为零。但是,如果int真的是具有该构造函数的类类型,则编写:

int i;

也将保证i为零,并且不会(至少,不在函数范围内)。

顺便说一句,不要对这一切太兴奋而意外调用所谓的“最令人头疼的解析”。

int i();

等于int i(void);,不是int i(0);。它声明了一个函数,而不是一个整数变量。

于 2012-10-04T09:14:25.613 回答
0

通常,对象具有复制构造函数,而指针不是对象,因此它们没有复制构造函数(或赋值运算符或析构函数)。更准确地说,指针依赖于默认的复制机制。

当您谈论auto_ptr或任何其他智能指针时,它们只是指针同名。但实际上它们是使用 RAII 机制的模板化对象。

CarPtr au_ptr2 = new Car();  // this is initialization not assignment

给出编译错误,因为相应CarPtr::CarPtr(...)的构造函数被制作explicit,所以它不接受=样式初始化。

于 2012-10-04T08:55:00.380 回答