(C ++)返回在函数内声明的对象的地址

时间:2015-04-12 00:46:15

标签: c++ pointers

所以这里有一些我已经读过和知道的事实。

1)在函数内部创建的对象(忽略新的/动态内存)不能返回(它们在函数完成后消失)

示例:

std::string* getTestString()
{
    std::string s = "STRING MADE IN FUNCTION";
    std::cout << "(INSIDE FUNCTION) DEREFERENCE (ADDRESS OF STRING): " << *(&s) << std::endl;
    std::cout << "(INSIDE FUNCTION) RETURN (ADDRESS OF STRING): " << &s << std::endl;
    return &s;
}
//main function
{
    std::string* s = getTestString();
    std::cout << "(IN MAIN) STRING POINTER: " << s << std::endl;
    std::cout << "(IN MAIN) ADDRESS OF (STRING POINTER): " << &s << std::endl;
    std::cout << "(IN MAIN) DEREFERENCE OF (STRING POINTER): " << *s << std::endl;
}

控制台的结果:

(INSIDE FUNCTION) DEREFERENCE (ADDRESS OF STRING): STRING MADE IN FUNCTION
(INSIDE FUNCTION) RETURN (ADDRESS OF STRING): 0x7fff85791040
(IN MAIN) STRING POINTER: 0x7fff85791040
(IN MAIN) ADDRESS OF (STRING POINTER): 0x7fff85791088
The program has unexpectedly finished.

TO SUMMARIZE:

1)在函数内部生成的字符串

2)返回String的地址

3)由于函数是DONE,因此String和stuff是GONE

4)在main中,返回String的ADDRESS,但是它(用于)指向的是GONE

5)你试图取消引用该地址,因为这些东西是GONE,它会崩溃

这是有道理的。

2)这个例子:

class TestObject
{
public:
    TestObject();
    ~TestObject();
    int getTestVariable();

private:
    int testVariable = 9999;
};

// IN MAIN.CPP

TestObject testTestObject1()
{
    TestObject testObject;
    std::cout<<"(INSIDE FUNCTION) ADDRESS OF TESTOBJECT: "<<&testObject<<std::endl;
    std::cout<<"(INSIDE FUNCTION) TESTOBJECT.VARIABLE: "<<testObject.getTestVariable()<<std::endl;
    return testObject;
}

TestObject* testTestObject2()
{
    TestObject testObject;
    std::cout<<"(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT): "<<&testObject<<std::endl;
    std::cout<<"(INSIDE FUNCTION) TESTOBJECT.VARIABLE: "<<testObject.getTestVariable()<<std::endl;
    return &testObject;
}

{
    TestObject tObject1 = testTestObject1();
    std::cout << tObject1.getTestVariable() << std::endl;
    std::cout << "(IN MAIN) ADDRESS OF (TESTOBJECT): " << &tObject1 << std::endl;

    TestObject* tObject2 = testTestObject2();
    std::cout << tObject2->getTestVariable() << std::endl;
    std::cout << "(IN MAIN) TESTOBJECT POINTER: " << tObject2 << std::endl;
}

控制台中的结果:

(INSIDE FUNCTION) ADDRESS OF TESTOBJECT: 0x7fff1aa91520
(INSIDE FUNCTION) TESTOBJECT.VARIABLE: 9999
9999
(IN MAIN) ADDRESS OF (TESTOBJECT): 0x7fff1aa91520

(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT): 0x7fff1aa914e0
(INSIDE FUNCTION) TESTOBJECT.VARIABLE: 9999
9999
(IN MAIN) TESTOBJECT POINTER: 0x7fff1aa914e0

TO SUMMARIZE:

无论我们在示例#1中发现什么,这个例子都有效! WTF BS! StackOverflow说的是#1是正确的,为什么你应该使用new / dyanmic内存来返回指针,但是#2有效,为什么?

1)testTestObject1()在函数内部生成一个TestObject

2)然后通过引用返回(??)它应该是值,但如果你看,地址是相同的?为什么呢?

3)testTestObject2()在函数内部生成一个TestObject

4)然后返回地址作为指针

5)但变量和对象仍然存在,即使它应该消失,因为函数是GONE

简称:

有人可以向我解释为什么即使在函数完成后,函数中的对象仍然存在?

Why should C++ programmers minimize use of 'new'?

When to use "new" and when not to, in C++?

When should I use the new keyword in C++?

3 个答案:

答案 0 :(得分:2)

你的第二种情况与第一种情况一样糟糕,你返回一个堆栈本地构造的对象的地址。在这种情况下,任何体面的编译器都应发出警告,并使用适当的警告级别(在g ++中使用-Wall -Wextra以确保捕获这些内容)。

我系统上的示例(除了由于定义不完整而导致的链接器错误,甚至没有警告标志):

  
    

第24行:warning: address of local variable 'testObject' returned

  

住在这里http://ideone.com/mc1ueG

如果你的程序编译并不代表你的程序&#34;工作&#34;。它只会引起未定义的行为(UB),这是您在C / C ++程序中可以获得的最变态的错误,因为有时它很难诊断。为什么在C / C ++中使用UB?因为你不想为你不能使用的东西买单,而编译器也不会对某些陈述执行严格的检查(尽管大部分时间都会发出警告)。这样的验证需要时间,而且,您不希望它们自动执行。

答案 1 :(得分:1)

你的简单例子很有效,因为你的代码很简单 - 你的对象使用的堆栈内存仍然存在,而且因为你还没有从main()返回,所以没有修改它。在连续调用类方法时,您的本地对象甚至在完全相同的位置具有完全相同的数据。

std::string不是一个简单的对象。在任何OS / C ++运行时,它很可能会进行大量的动态内存分配,这样如果在调用析构函数后引用该对象,则进程将失败。

正如其他人已经指出的那样 - 你的行为让人感到意外,在不同的情况下,未定义的东西会有所不同。

答案 2 :(得分:0)

如前所述,你很幸运没有得到未定义的行为,因为你的内存没有被其他程序使用,但如果我们强制程序使用你的函数返回的指针使用强制分配的新操作符放置将会发生什么某个指针的内存:

TestObject* testTestObject2()
{
/*static*/   TestObject testObject;
  std::cout<<"(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT):"<<&testObject<<std::endl;
  std::cout<<"(INSIDE FUNCTION) TESTOBJECT.VARIABLE: "<<testObject.getTestVariable()<<std::endl;
  return &testObject;
}

 TestObject* tObject2 = testTestObject2();

 TestObject * tObject3 = new  (tObject2) TestObject;

 std::cout << tObject2->getTestVariable() << std::endl;

输出:

---&GT;这里编译器不保护你的内存“不确定行为”,因为我使用new将数据放在同一个指针中:

(IN MAIN) ADDRESS OF (TESTOBJECT): 0x7ffffddcb0b8
(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT): 0x7ffffddcafe8
(INSIDE FUNCTION) TESTOBJECT.VARIABLE: 9999
-35868696  (undefined behavior)
(IN MAIN) TESTOBJECT POINTER: 0x7ffffddcafe8

让我们看看我们是否通过静态关键字保护您的返回指针:

TestObject* testTestObject2()
{
static   TestObject testObject;
  std::cout<<"(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT): "<<&testObject<<std::endl;
  std::cout<<"(INSIDE FUNCTION) TESTOBJECT.VARIABLE: "<<testObject.getTestVariable()<<std::endl;
  return &testObject;
}

输出: 这里程序使用不同的地址来存储返回值

的数据
(IN MAIN) ADDRESS OF (TESTOBJECT): 0x7fff479bd8c8
(INSIDE FUNCTION) RETURN (ADDRESS OF TESTOBJECT): 0x6021dc
(INSIDE FUNCTION) TESTOBJECT.VARIABLE: 9999
9999  (data is intact)
(IN MAIN) TESTOBJECT POINTER: 0x6021dc