new로 할당한 메모리를 줄일 수 있는 방법이 없을까요?

dltkddyd의 이미지

malloc으로 할당된 메모리는 realloc로 확장되거나 축소될 수 있습니다. 또 이런 함수가 new와 같은 예약어보다 할당속도가 더 빠르다는 것을 알게되고 나서부터 주로 malloc과 같은 메모리 관련 함수를 쓰려 했습니다. 그런데 클래스를 기본단위로 하는 메모리를 이 함수로 할당할 경우에는 생성자가 호출되지 않는다는 문제가 발생하더군요. 만약에 클래스가 포인터를 멤버로 갖지 않는 경우에는 문제될 게 없겠으나, 포인터를 멤버로 갖는 경우에 이 함수로 메모리를 할당할 경우에는 같은 메모리를 공유하는 문제가 발생하던데요. new로 할당된 메모리를 동일한 주소에서 줄일 수 있는 방법이 있을까요? 반복문을 돌려서 깨는 법도 있긴 하지만, 이런 메모리 깨기 전략은 자칫 과부하를 일으킬 수 있기 때문에 가능한 피라려고 합니다. 방법좀 알려주세요.

mirheekl의 이미지

이걸 이용하면 이미 할당받은 주소에 대해 생성자를 호출할 수 있습니다. http://www.parashift.com/c++-faq/placement-new.html

또는, 아예 글로벌 new를 원하는대로 바꿀 수도 있습니다. http://oroboro.com/overloading-operator-new/

이들을 적절히 이용해서, 가급적 기본적인 C++의 신택스를 바꾸지 않는 형태로 구현하시면 좋을듯 합니다. 매번 new의 사용을 의도적으로 피하고 클래스에마저 malloc등을 계속 사용하면 코드를 이해하기 힘들어질 듯 합니다.

--

dltkddyd의 이미지

new로 할당된 메모리를 realloc로 재할당하며 축소하는 방법은 없나요? 또는 new로 그 주소에서 축소하는 방법은 없는지요?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

kukyakya의 이미지

byte단위 카피가 가능한 객체가 아니면 불가능합니다.

realloc 함수 자체가 이미 할당된 내용을 새로 할당한 지역으로 복사할 가능성이 있기 때문에 C++에서는 사용이 장려되지 않습니다.

다만 trivially copyable type이라면 realloc을 사용하는 것이 성능상 이득을 볼 가능성이 있습니다.

@그런데 도대체 뭘 '축소'하고 싶으신건가요? 객체의 크기야 컴파일 타임에 정해져있는거니 이건 축소시킬 수가 없을텐데요

dltkddyd의 이미지

다음과 같은 코드에서

#include <iostream>
using namespace std;
#include <cstdio>
class Test {
public:
	Test() {
		cout<<"Test"<<endl;
	}
	~Test() {
		cout<<"~Test"<<endl;
	}
};
 
int main() {
	/*char* obj1=new char[5];
	obj1[0]='a';obj1[1]='b';obj1[2]='c';obj1[3]='d';obj1[4]='e';      //obj1[5]='f';obj1[6]='\0';
	cout<<obj1<<endl;
	printf("%p\n",obj1);
 
	//delete[] obj1;
 
	obj1=new(obj1) char[10];
 
	printf("%p\n",obj1);
	cout<<obj1<<endl;
 
	delete[] obj1;*/
 
	Test* obj2=new Test[5];
 
	obj2=new(obj2) Test[10];
 
	delete[] obj2;
	return 0;
}

생성자는 5, 10 이렇게 해서 총 15번 호출이 됐습니다. 그럼 소멸자도 15번 호출될 것으로 예상했는데, 그렇지 않네요. 또는 같은 메모리에 겹쳐서 할당이 됐으니 적어도 10번은 호출돼야하는 것은 아닌가라고 생각했는데, 5번만 소멸자가 호출됩니다. 이렇게 되면 new()의 사용을 안전하다고 할 수 없는 것 아닌가요? 어딘가 좀 불안해보이는데요? 섣불른 짐작으로 욕얻어먹을 것 같으면서도 질문드립니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

mirheekl의 이미지

플레이스먼트 new를 사용해 생성자를 호출한 객체는 소멸자도 직접 호출해줘야 합니다. xxx->~Test() 이렇게요. delete는 new로 할당한 메모리만 관리하니까요.

	Test* obj2=new Test[5]; // obj2는 Test[5] 객체에 대한 주소를 갖습니다. 즉 생성자 5번 호출. 
 
	obj2=new(obj2) Test[10]; // obj2에 대해 Test[10]에 해당하는 생성자를 호출합니다. 즉 생성자 10번 호출. obj2 주소 자체는 **안 바뀝니다.**
 
	delete[] obj2; // 내부 자료구조에는 Test[5]에 대한 정보만 존재합니다. 따라서 소멸자도 5회만 호출되는 것이죠. 

뭔가 근본적으로 오해를 하고 계신 것 같네요. 제가 드렸던 말씀은, 메모리 관리를 직접 구현할 경우 발생하는 생성자 소멸자 호출 문제를 placement new로 해결하라는 뜻이었습니다. 보통은 커스텀 메모리관리를 위해 커다란 영역을 malloc이나 virtualalloc등등으로 한번에 할당해놓고 이걸 쪼개서 사용하면서, 그렇게 만들어낸 메모리 주소에다가 생성자와 소멸자를 호출해주기 위한 수단으로 사용하는 것이죠. 저게 딱히 메모리 재배치를 해주는게 아닙니다. 뭐랄까.. 클래스에 FuncA()랑 FuncB()를 퍼블릭으로 선언하고 이걸 수동으로 호출하는 것과 구조적으로는 아무런 차이가 없습니다.

저 코드 자체는 그대로 사용하면 문제가 발생할수밖에 없는게, 소멸자 수동 호출이 누락된것도 문제이지만, Test[5]에 해당하는 영역만 메모리를 할당해놓고 그 포인터를 Test[10]으로 전용한다는 겁니다. 지금이야 객체 내에서 별 일을 하지 않으니 에러도 발생하지 않은 것이지만, 실 사용에서는 힙 커럽션이 발생할 확률이 대단히 높습니다.

써놓고 보니 학교 시험문제 등으로 내놓기 좋은 예제인것 같기도 합니다. 생성자와 소멸자가 각각 몇번 호출될지를 적고 그 이유를 설명하시오 이렇게..

--

ifree의 이미지

malloc 이 얼마나 빠를지는 모르겠지만,
가능하면, new, delete 를 사용해서 원래의 C++ 방법대로 프로그램을 작성하세요.
프로그램의 빠르기도 중요하지만, 이의 유지 보수와 업그레이드 또한 이에 못지 않게 중요합니다.

jick의 이미지

꼭 메모리 영역의 크기를 늘였다 줄였다 해야 한다면, class에는 메모리 영역을 가리키는 포인터만 넣어두고 그 포인터가 가리키는 영역을 class constructor에서 malloc을 이용해서 잡아보세요.

클래스 자체를 malloc으로 할당한다는 얘기는 들어본 적이 없습니다. (뭐 100% 안된다는 얘기는 아니지만 옆에서 누가 그러면 말릴랍니다.)

노파심에 말씀드리자면, C가 아닌 C++로 프로그램을 짜겠다고 마음을 먹으셨으면 가급적이면 C++의 기본 개념을 따라가는 게 유지보수하기도 좋고 나중에 본인이나 다른 사람이 코드를 이해하기도 훨씬 낫습니다. C++의 기본적인 방식이 답답해 보여도 그게 다 수십 년 동안 수많은 사람들이 삽질하면서 "아 이렇게 짜면 나중에 망하는구나"를 깨달은 지혜가 농축된 겁니다.

익명 사용자의 이미지

> 포인터를 멤버로 갖는 경우에 이 함수로 메모리를 할당할 경우에는 같은 메모리를 공유하는 문제가 발생하던데요. new로 할당된 메모리를 동일한 주소에서 줄일 수 있는 방법이 있을까요?

이 두 문장이 어떤 연관을 가지는지 이해하기가 어렵네요. 저는 근본적으로 '메모리를 공유하는 문제'를 '메모리를 동일한 주소에서 줄이는 방법'으로 풀려는 시도 자체가 이상하게 보입니다. 설명해주실 수 있나요?

dltkddyd의 이미지

*this안의 하부 멤버인 포인터를 새로 확장하거나 줄일 때 realloc를 사용했기 때문에 포인터가 공유되더라도 문제될 것은 없었습니다. 그러니까 자기 자신을 확장하거나 줄일 용도로 realloc를 사용했습니다. 그럴 때는 포인터 공유의 문제가 없었습니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

gilgil의 이미지

객체가 생성될 경우 3가지를 수행하게 됩니다( http://www.gilgil.net/10409 ).

1. 메모리 할당.
2. constructor 호출
3. vmt 세팅

이 3가지를 동시에 할 수 있는 것이 new이구요, malloc은 위 3가지중에 1번 기능을 충족시키는 역할만 할 수 있습니다.
사실 프로그램을 작성하다 보면 위 3가지를 따로 구분해서 호출해야 하는 경우는 거의 없습니다. 예외 사항이라고 한다면 object pool pattern을 사용하는 경우 정도?

memory관리를 realloc과 같은 API를 이용해서 별도로 관려ㅎ나느 방식을 추구한다면, shallow copy & deep copy의 차이에서부터 오게 되는 memory access violation error 지옥을 만나게 될 겁니다.

결론 : 남들이 사용하는 보편적인 방식을 사용하심이 좋음.

dltkddyd의 이미지

아래의 코드에서 new로 재할당시 obj[3], obj[4]의 메모리가 깨질까요?

#include <iostream>
using namespace std;
#include <cstdio>
int main() {
	char* obj1=new char[5];
	obj1[0]='a';obj1[1]='b';obj1[2]='c';obj1[3]='d';obj1[4]='\0';
	cout<<obj1<<endl;
	printf("%p\n",obj1);
	obj1=new(obj1) char[2];//여기서 메모리를 재할당되는데, [3], [4] 메모리가 해제되는지요?
 
	printf("%p\n",obj1);
	cout<<obj1<<endl;
 
	delete[] obj1;
 
	return 0;
}

obj1이 가리키는 공간을 축소하면 재할당하고 싶은데, 어떻게 하죠? realloc, malloc를 사용하지 않고요. 클래스를 타입으로 사용할 경우까지 감안해서 재할당을 하고싶은데요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

kukyakya의 이미지

해제되지 않습니다. C++ 표준 내에선 불가능합니다.

dltkddyd의 이미지

그럼 메모리를 줄이는 것이 아니라 확장할 때에는 누수라는 문제가 발생하지 않을까요? 가령

obj1=new(obj1) char[10];

이라고 코드를 고쳤을때 말입니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

mirheekl의 이미지

저 구문은 char[10]에 해당하는 생성자를 호출해줄 뿐, 메모리 할당에 대해서는 아무 일도 하지 않습니다. "메모리를 줄이거나 확장하는게 아닙니다!" 뭔가 realloc의 C++버전을 기대하신 것 같은데 그런 게 아닙니다.

원하시는 게 어떤 건지는 알겠는데, 다른 분들의 말씀을 믿고 그냥 안심하고 일반적인 메모리 관리를 사용하시고 다른 로직에 집중하시면 좋을것 같네요.

말씀하신 부분의 최적화를 통해 억대의 차이를 만들 수 있는 경우도 분명 있지만, 그런 작업을 하고 계신 경우에는 아마 이 질문글은 애초에 만들어지지도 않았을 겁니다.

--

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.