自动变量销毁的迷惑

fancystyle 2010-03-08 07:53:04

// HelloCpp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <vector>

#include <iostream>
using namespace std;

class Fool {
public:
~Fool()
{
cout<<"Fool desconstructor called!"<<endl;
}
void say()
{
cout<<"hello"<<endl;
}
};

//为啥这个没有编译警告,arr不是自动变量么.
Fool * GetFool()
{
std::vector<Fool> arr(3);
return &arr[0];
}

//GetFool2 编译会有这些错误
///Warning 1 warning C4172: returning address of local variable or temporary

Fool * GetFool2()
{
Fool f;
return &f;
}

Fool * GetFool3()
{
Fool* f=new Fool;
return f;
}



int main() {
Fool* f= GetFool();
f->say();
system("PAUSE");
return 0;
}



如题. GetFool2()函数编译时有警告.我理解.f为自动变量,函数结束即销毁.
//为啥这个没有编译警告,arr不是自动变量么.
Fool * GetFool()
{
std::vector<Fool> arr(3);//arr也为自动变量啊,从打印运行结果看,函数结束arr一样销毁.为啥没有编译警告?这种操作是否合法?为什么?
return &arr[0];
}

我不清楚vector的实现,同样的道理,我用数组实现,不用vector
Fool * GetFool()
{
Fool f;
Fool arr[1]={f};
return &arr[0];
}
这样也没有编译警告?
请大家帮忙解惑
...全文
161 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
mediawizard 2010-03-09
  • 打赏
  • 举报
回复
楼主的GetFool函数没有报警告我想是因为vector重载了[]操作符,所以编译器认为GetFool函数返回的是另一个函数返回的变量的地址,所以才没有警告。
此外,在最后return &arr[0];对应的汇编程序中,会调用vector的析构函数。在~vector里边会调用_Destroy()和内存分配器(allocator)的deallocate()来释放内存。所以我感觉之所以没有出问题,其实只是侥幸没有人去动分配器刚刚释放的内存(堆管理器没有回收那个内存页)而已。当然,如果返回来的结果是一个基本类型/可以调用拷贝构造函数的对象的话,就另当别论了。

而GetFool2()那种返回形式是一定要避免的,原因大家都明白的。
((Fool*)(NULL))->say()没有崩溃也只是因为在say()里边没有对NULL的this做提领操作而已,否则还是要崩的。
fox000002 2010-03-08
  • 打赏
  • 举报
回复
下面这个肯定是不对的

至于有没有警告,那可以看成代码欺骗了编译器吧

例如下面的代码

class CA
{
public:
char p[2];
}

char * createCB()
{
CA a;
return a.p; // 这个当然是有问题的
}


再看看这个

class CA
{
public:
CA()
{
std::cout << "CA()!" << std::endl;
p = new char[2];
}

~CA()
{
std::cout << "~CA()!" << std::endl;
delete[] p;
}

char *p;
};

char * createCB()
{
CA a;
return a.p; // 这个当然是有问题的
}
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
TO #13

wstring AnsiToUnicode(const char* buf)
{
int len = ::MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0);
if (len == 0) return L"";

std::vector<wchar_t> unicode(len);//看这里.这不是局部变量么?
::MultiByteToWideChar(CP_ACP, 0, buf, -1, &unicode[0], len);

return &unicode[0];//此处返回时wstring赋值操作符的操作,COPY了指针所指的字符串内容了么?
}


那么如果我这样写也是可以编译的
[code=C/C++]
wchar_t * AnsiToUnicode(const char* buf)
{
int len = ::MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0);
if (len == 0) return L"";

std::vector<wchar_t> unicode(len);//看这里.这不是局部变量么?
::MultiByteToWideChar(CP_ACP, 0, buf, -1, &unicode[0], len);

return &unicode[0];//此处返回时没有构造了吧.那此函数是不是和上个相比,就是错误的了?
}
fox000002 2010-03-08
  • 打赏
  • 举报
回复
那这个不会出问题,构造临时对象时拷贝字符串内容了

后面用的不是那个返回的地址
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
引用 11 楼 fox000002 的回复:
还得看看 qp::StringW 是怎么定义的

如果用 wchar_t 指针构造了一个 qp::StringW 临时对象,这应该没有问题

老邓告诉我 qp::StringW 可以替换成wstring 用
fox000002 2010-03-08
  • 打赏
  • 举报
回复
还得看看 qp::StringW 是怎么定义的

如果用 wchar_t 指针构造了一个 qp::StringW 临时对象,这应该没有问题
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
多谢楼上的二位,你们的回复又让我产生了新的问题
引用 6 楼 stardust20 的回复:
结果没错是因为你没有用到有关系这个类非静态成员变量,没用到类的非静态成员变量
((Fool*)(NULL))->say();用空的Fool *也可以正确运行。。输出hello的

这种写法的运行结果,我也没有理解。很吃惊,这啥这也能运行?!您的代码我未能理解,say()方法是静态成员变量?为什么是静态的了?
stardust20 2010-03-08
  • 打赏
  • 举报
回复
不理解老邓为什么这么用。。。帮楼主顶起。。。
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
引用 5 楼 yuzl32 的回复:
return &arr[0];//指向了其内部数据结构,编译器不知道它是不是局部变量,说不定它是指向外部某个变量


那这种写法是不是不建议或者压根就是潜在错误的?如果是这样,老邓的代码是否也有问题?
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
引用 3 楼 stardust20 的回复:
编译器没警告也不代表是合法的。。。int a[10]; a[11]=1;
数组越界了。。但vs2008也不会有警告啊。。。

我的迷惑来自于此帖三楼,老邓写的函数
http://topic.csdn.net/u/20091015/15/de2a33c4-9e56-4ed2-bd53-a27623140bb2.html


qp::StringW Global::AnsiToUnicode(const char* buf)
{
int len = ::MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0);
if (len == 0) return L"";

std::vector<wchar_t> unicode(len);//看这里.这不是局部变量么?
::MultiByteToWideChar(CP_ACP, 0, buf, -1, &unicode[0], len);

return &unicode[0];
}


请帮忙解释
stardust20 2010-03-08
  • 打赏
  • 举报
回复
结果没错是因为你没有用到有关系这个类非静态成员变量,没用到类的非静态成员变量
((Fool*)(NULL))->say();用空的Fool *也可以正确运行。。输出hello的
yuzl32 2010-03-08
  • 打赏
  • 举报
回复
return &arr[0];//指向了其内部数据结构,编译器不知道它是不是局部变量,说不定它是指向外部某个变量
yuzl32 2010-03-08
  • 打赏
  • 举报
回复
这样就有警告了,因为arr是局部变量。

std::vector<Fool>* GetFool()
{
std::vector<Fool> arr(3);
//return &arr[0];
return &arr;
}
stardust20 2010-03-08
  • 打赏
  • 举报
回复
编译器没警告也不代表是合法的。。。int a[10]; a[11]=1;
数组越界了。。但vs2008也不会有警告啊。。。
fancystyle 2010-03-08
  • 打赏
  • 举报
回复
引用 1 楼 stardust20 的回复:
Fool * GetFool2()
{
    Fool f;
    return &f;
}
就算没警告,这边返回局部变量的引用也是错的啊。。。。

我知道它是错的,按照我的理解
GetFool()也是错的,结果是没有错,我就晕了.
stardust20 2010-03-08
  • 打赏
  • 举报
回复
Fool * GetFool2()
{
Fool f;
return &f;
}
就算没警告,这边返回局部变量的引用也是错的啊。。。。

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧