[완료] if (((_SIZT)(-1) / _Count) < sizeof (_Ty)) 이것과 if (((_SIZT)(-1)) < sizeof (_Ty) * _Count) 의 차이점은..

ikpil의 이미지

안녕하세요? 할당자에 대해서 공부를 하다가.
xmemory 첫번째 부근에서 이런것을 보게 되었습니다.

_SIZT 는 unsigned int 입니다;

if (((_SIZT)(-1) / _Count) < sizeof (_Ty))

이런것을 보았는데, 처음에 나누기에 대해서 햇갈려서, 이게 무엇을 뜻하는거지 했습니다.
보통은..

if (((_SIZT)(-1)) < sizeof (_Ty) * _Count)
이런식으로 생각할텐데 말이죠..

분명 차이가 있을꺼 같다는 생각이 드는데요.

질문, 첫번째 식과 두번째 식의 차이점은 어떤게 있을까요?
(암시적으로 성능에 더 좋은 문법이구나.. 합니다만, 그 원리에 대해서 모르겠습니다)

- 함수 정의 입니다 -
template inline
_Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)
{ // check for integer overflow
if (_Count <= 0)
_Count = 0;
else if (((_SIZT)(-1) / _Count) < sizeof (_Ty))
_THROW_NCEE(std::bad_alloc, NULL);

// allocate storage for _Count elements of type _Ty
return ((_Ty _FARQ *)::operator new(_Count * sizeof (_Ty)));
}

ikpil의 이미지

요즘 점점 기초 수학(산수)에서 쩔쩔매는거 같습니다. 나누기와 곱하기의 작용을 햇갈려 하다니..

klyx의 이미지

어떤 구문인지는 잘 모르겠지만, ((_SIZT)(-1) / _Count) < sizeof (_Ty) 와 ((_SIZT)(-1)) < sizeof (_Ty) * _Count 는 _Count가 실수가 아니라면 전혀 다른 결과가 됩니다.
1/2 != 1.0/2.0 이니까요...

ikpil의 이미지

전제조건은
unsigned int 일 경우입니다.

그런데 순간 잊어먹고 있었습니다.
"실수일때는 전혀 다른거였었군" 하고 말입니다.

ikpil의 이미지

두 방법 모두, 10억번 루프돌려 테스트 해보았습니다만, 동일합니다.
나누기나 곱하기나 내부적으론 동일한 연산인거 같습니다.

그리고 외국 애들은 첫번째 방법의 사고 방식이 더 편한듯 합니다;

#include iostream
#include windows.h

int main(void)
{
DWORD check = GetTickCount();

for(int i = 0; i < 1000000000; i++)
{
if((UINT)(-1) / 3 < sizeof(int))
{
}
}

std::cout << GetTickCount() - check << std::endl;

}

doldori의 이미지

성능과는 관계없고 오버플로우(*)를 방지하기 위한 것입니다.
(unsigned)-1은 UINT_MAX와 같습니다.
만약 ((_SIZT)(-1)) < sizeof (_Ty) * _Count)로 코딩한다면 이 결과는 항상 거짓이 됩니다.
어떤 unsigned int의 곱도 UINT_MAX보다 클 수는 없기 때문입니다.
그렇다면 이 함수는 언제나 ::operator new()를 실행하게 됩니다.
이 구현체에서 UINT_MAX의 값을 간단하게 42억이라고 하죠.
그럼 ::operator new()가 할당할 수 있는 한계는 4GB가 됩니다.
만약 sizeof(_Ty) == 8이고 _Count == 10억이라고 합니다.
이 함수를 호출할 때는 8GB를 요청한 것이지만 연산 과정의 오버플로우로 인하여
그보다 훨씬 적은 메모리만 할당하게 될 것입니다. 당연히 이것은 잘못된 것이죠.

그럼 원래 코드대로 ((_SIZT)(-1) / _Count) < sizeof (_Ty)로 하면 어떨지 생각해 봅시다.
< 연산자의 왼쪽은 (4GB / 10억)이므로 4가 되고 오른쪽은 8입니다.
그럼 이것은 할당할 수 있는 최대값보다 큰 메모리를 요청한 것이므로
std::bad_alloc 예외를 던지게 되는 것입니다.

(*) 편의상 오버플로우라고 했지만 엄밀히 말하면 무부호 정수형에는 오버플로우가 없습니다.
연산 결과가 UINT_MAX보다 크면 잘 정의된 규칙에 의해 wrap-around 됩니다.

ikpil의 이미지

몰랐던 사실을 알게 되었습니다.

댓글 달기

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