shared_ptr과 포인터 변환에 대한 질문2

telepathy070의 이미지
class StringContainer
{
public:
    StringContainer();
    char tmp_array[32];
};
 
StringContainer::StringContainer()
{
    memset(tmp_array, 0, sizeof(tmp_array));
    strcpy(tmp_array, "dream comes true!!!");
}
 
 
long long extern_raw_cstring_address;
std::shared_ptr<StringContainer> ext_cr;
 
function A()
{
    std::shared_ptr<StringContainer> cr = shared_ptr<StringContainer>(new StringContainer());
    extern_raw_cstring_address = (long long)(reinterpret_cast<void * >(&cr));  //shared_ptr 주소 출력
 
    ext_cr = cr;  //외부 변수에 대입하여 shared_ptr 함수를 벗어나도 삭제되지 않게 막기
 
}
 
function B()
{
    StringContainer* ext_data = ext_cr.get();
    TRACE(ext_data->tmp_array);   //정상적으로 출력됨
    TRACE("\r\n");
 
    std::shared_ptr<StringContainer> * test_cstring = reinterpret_cast<shared_ptr<StringContainer> * >(extern_raw_cstring_address); //캐스팅된 변수가 이상함1
    StringContainer* recover_raw_cstring = ( * test_cstring).get();  //내부 데이터 역시 깨져있음2
    TRACE((*recover_raw_cstring).tmp_array);  //여기서 종료됨3
    TRACE("\r\n");
 
}

일단 제가 하려는게 다음과 같은겁니다.

  1. 함수 A()에서 shared_ptr를 만들고 그 주소를 저장합니다.

  2. 함수 B()에서 그 주소를 가지고 shared_ptr를 다시 가져옵니다.

하지만 함수B에서 실제 주소인 extern_raw_cstring_address를 가지고 shared_ptr를 다시 불러오면 데이터가깨져있어요

함수 A()벗어났을때 shared_ptr이 삭제된건 절대아니구요 (왜냐하면 deleter함수를 등록해서 확인해보면 확실히 ext_cr때문에 삭제 안시켜요)

왜 shared_ptr를 정상적으로 메모리에서 가져오지 못할까요?

함수B()를 함수 A() 끝나기 전에 불러도 정상적으로 출력이 되는데...함수 A()가 종료된뒤 함수 B()를 부르면 에러로 종료됩니다.

ktd2004의 이미지

shared_ptr은 내부의 pointer를 공유하는 그냥 객체입니다.

함수 A 종료시점에 cr과 ext_cr이 가지고 있는 내부 pointer는 유효하지만 cr은 종료되어버리므로,
그 cr의 pointer를 가지고 있는 extern_raw_cstring_address는 유효하지 않은 cr의 pointer를 가지고 있게 됩니다.

telepathy070의 이미지

정말 그렇더라구요..
그래서 shared_ptr를 클래스 넣어서 관리하는 것으로 변경하고 있습니다.

shint의 이미지

테스트해봤습니다.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://blog.naver.com/lobo_prix/220421546490

shared_ptr 을 전역변수로 사용하더라도. main함수가 return 될때.
소멸자가 자동으로 호출됩니다. delete p; 를 하지 않아도 되는 경우가 있습니다.

shared_ptr 을 지역변수로 사용하면. 함수가 return 될때. 소멸자가 함께 호출됩니다.
shared_ptr 은 같은 주소를 함께 참조하면 오류가 발생합니다.

---------------------------------------------
TRACE() 는 255 자를 넘을 경우. 주의해야 합니다.
사용방법은 printf() 와 같은 방식입니다.

TRACE 매크로
https://msdn.microsoft.com/ko-kr/library/4wyz8787%28v=vs.90%29.aspx

https://msdn.microsoft.com/en-us/library/6w95a4ha.aspx

---------------------------------------------
char buf[1024];
sprintf(buf, "%s", "test");
OutputDebugString(buf); 도 사용하실 수 있습니다.

---------------------------------------------
윈도우에서 콘솔화면을 띄워서. printf()를 사용할 수 있습니다.
AllocConsole();
freopen("CONOUT$", "wt", stdout);

콘솔 윈도우 닫기
FreeConsole();

int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );
 
TRACE( "The value of x is %d\n", x );
 
TRACE( "x = %d and y = %d\n", x, y );
 
TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

#include <iostream>
#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <atomic>
 
 
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
#include <functional>
 
 
using namespace std;
 
 
class StringContainer
{
public:
	StringContainer();
	virtual ~StringContainer()
	{
		printf("~StringContainer() 소멸자 : %x : %s\n", this, m_myname.c_str());
	}
 
	string m_myname;
	char tmp_array[32];
};
 
StringContainer::StringContainer()
{
	printf("StringContainer() 생성자 : %x : %s\n", this, m_myname.c_str());
	printf("this         :  %x\n", this);
	printf("tmp_array    :  %x\n", tmp_array);
 
	memset(tmp_array, 0, sizeof(tmp_array));
	strcpy(tmp_array, "dream comes true!!!");
}
 
 
long long extern_raw_cstring_address;
std::shared_ptr<StringContainer> ext_cr;
 
 
 
//function A()
void A()
{
	printf("---------------------------------------------------------A()\n");
	StringContainer * p = new StringContainer();
	p->m_myname = "A()";
 
#if 0
포인터를 공유하는 방법??
	std::shared_ptr<StringContainer>* p = (shared_ptr<StringContainer>*)new StringContainer();
    shared_ptr<StringContainer> sp2 = shared_ptr<StringContainer>(p);
    shared_ptr<StringContainer> sp1(p);
#endif
 
	//shared_ptr 을 지역변수로 사용하면. 함수가 return 될때. 소멸자가 함께 호출됩니다. 
	//shared_ptr 은 같은 주소를 함께 참조하면 오류가 발생합니다.
    shared_ptr<StringContainer> sp1(p);
 
	extern_raw_cstring_address = (long long)p;
 
	printf("A() p                : %x\n", p           );
	printf("A() p->tmp_array     : %x\n", p->tmp_array);
	printf("A() p->tmp_array     : %s\n", p->tmp_array);
	printf("_msize               : %d\n", _msize(p)   );
}
 
//function B()
void B()
{
	printf("---------------------------------------------B()\n");
 
    std::shared_ptr<StringContainer> * test_cstring = reinterpret_cast<shared_ptr<StringContainer> * >(extern_raw_cstring_address); //캐스팅된 변수가 이상함1
 
	StringContainer * p = (StringContainer*) test_cstring;
 
	printf("BB() p               : %x\n", p);
	printf("BB() p->tmp_array    : %s\n", p->tmp_array);
	printf("_msize               : %d\n", _msize(p));
}
 
void A2()
{
	printf("---------------------------------------------------------A2()\n");
	StringContainer * p = new StringContainer();
	p->m_myname = "A2()";
	ext_cr = shared_ptr<StringContainer>(p);
	printf("A2() p->tmp_array    : %x\n", p->tmp_array);
	printf("A2() p->tmp_array    : %s\n", p->tmp_array);
	printf("_msize               : %d\n", _msize(p));
} 
 
void B2()
{
	printf("---------------------------------------------B2()\n");
	StringContainer * p = ext_cr.get();
 
	printf("B2() p->tmp_array    : %x\n", p->tmp_array);
	printf("B2() p->tmp_array    : %s\n", p->tmp_array);
	printf("_msize               : %d\n", _msize(p));
//shared_ptr 을 전역변수로 사용하더라도. main함수가 return 될때.
//소멸자가 자동으로 호출됩니다. delete p; 를 하지 않아도 되는 경우가 있습니다.
}
 
 
int n;
void AA()
{
	printf("---------------------------------------------------------AA()\n");
	StringContainer * p = new StringContainer();
	p->m_myname = "AA()";
 
	n = (int)p;
 
	printf("AA() p    : %x\n", p);
	printf("AA() p    : %s\n", p->tmp_array);
	printf("_msize    :  %d\n", _msize(p));
}
 
void BB()
{
	printf("---------------------------------------------BB()\n");
 
	StringContainer * p = (StringContainer*)n;
 
	printf("BB() p    : %x\n", p);
	printf("BB() p    : %s\n", p->tmp_array);
	printf("_msize    :  %d\n", _msize(p));
	delete p;
}
 
void F1()
{
	printf("---------------------------------------------------------F1()\n");
	char * p = new char[100];
	strcpy(p, "test");
	n = (int)p;
 
	printf("F1() p    : %x\n", p);
	printf("F1() p    : %s\n", p);
	printf("_msize    :  %d\n", _msize(p));
}
 
void F2()
{
	printf("---------------------------------------------F2()\n");
 
	char * p = (char*)n;
 
	printf("F2() p    : %x\n", p);
	printf("F2() p    : %s\n", p);
	printf("_msize    :  %d\n", _msize(p));
	delete [] p;
}
 
 
int main(int argc, char** argv) 
{
 
	A();
	B();
 
	A2();
	B2();
 
	AA();
	BB();
 
	F1();
	F2();
 
	printf("main end\n");
	return 0;
}
 
 
출력 결과
---------------------------------------------------------A()
StringContainer() 생성자 : 3d3f08 :
this         :  3d3f08
tmp_array    :  3d3f10
A() p                : 3d3f08
A() p->tmp_array     : 3d3f10
A() p->tmp_array     : dream comes true!!!
_msize               : 40
~StringContainer() 소멸자 : 3d3f08 : A()
---------------------------------------------B()
BB() p               : 3d3f08
BB() p->tmp_array    : dream comes true!!!
_msize               : 40
---------------------------------------------------------A2()
StringContainer() 생성자 : 3d3f08 :
this         :  3d3f08
tmp_array    :  3d3f10
A2() p->tmp_array    : 3d3f10
A2() p->tmp_array    : dream comes true!!!
_msize               : 40
---------------------------------------------B2()
B2() p->tmp_array    : 3d3f10
B2() p->tmp_array    : dream comes true!!!
_msize               : 40
---------------------------------------------------------AA()
StringContainer() 생성자 : 3d3f58 :
this         :  3d3f58
tmp_array    :  3d3f60
AA() p    : 3d3f58
AA() p    : dream comes true!!!
_msize    :  40
---------------------------------------------BB()
BB() p    : 3d3f58
BB() p    : dream comes true!!!
_msize    :  40
~StringContainer() 소멸자 : 3d3f58 : AA()
---------------------------------------------------------F1()
F1() p    : 3d3fa8
F1() p    : test
_msize    :  100
---------------------------------------------F2()
F2() p    : 3d3fa8
F2() p    : test
_msize    :  100
main end
~StringContainer() 소멸자 : 3d3f08 : A2()
 
--------------------------------
Process exited after 0.4688 seconds with return value 0
계속하려면 아무 키나 누르십시오 . . .
댓글 첨부 파일: 
첨부파일 크기
Package icon test shared_ptr 과 new 사용방법.zip388.33 KB

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

telepathy070의 이미지

그렇지 않아도 2번째 링크에서 지적한 문제가 저한테도 발생해서
http://blog.naver.com/lobo_prix/220421546490

좀더 shared_ptr에 대해서 공부해봐야겠네요

테스트 감사해요

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.