我认为以下两个是相同的:(使用C ++ 14)
std::unique_ptr<char[]> buf(std::make_unique<char[]>(size));
std::unique_ptr<char[]> buf(new char[size]);
但是当我编译这两个并测量每个实际花费的时间时,结果是非常意外的。这是我的测试代码:
#include <stdint.h>
#include <memory>
#include <chrono>
#include <sys/time.h>
#include <sys/types.h>
class Elapsed
{
public:
Elapsed()
{
start();
}
int64_t getElapsedMicro()
{
std::chrono::steady_clock::time_point end(std::chrono::steady_clock::now());
return std::chrono::duration_cast<std::chrono::microseconds>(end - mStart).count();
}
void start(void)
{
mStart = std::chrono::steady_clock::now();
}
private:
std::chrono::steady_clock::time_point mStart;
};
static void loop(char *p, size_t aSize)
{
Elapsed sElapsed;
for (size_t i = 0; i < aSize; i++)
{
if (*(p + i) == 0)
{
*(p + i) = i % 128;
}
else
{
*(p + i) = i % 128;
}
}
printf("%ld usec to loop buffer\n", sElapsed.getElapsedMicro());
}
int32_t main(int32_t aArgc, char *aArgv[])
{
int32_t sChoice = aArgv[2][0] - '0';
size_t sSize = strtoll(aArgv[1], NULL, 10);
Elapsed sDelete;
switch (sChoice)
{
case 1:
{
printf("std::unique_ptr<char[]> buf(std::make_unique<char[]>(%zu));\n", sSize);
Elapsed sElapsed;
std::unique_ptr<char[]> buf(std::make_unique<char[]>(sSize));
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf.get(), sSize);
sDelete.start();
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
case 2:
{
printf("std::unique_ptr<char[]> buf(new char[%zu]);\n", sSize);
Elapsed sElapsed;
std::unique_ptr<char[]> buf(new char[sSize]);
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf.get(), sSize);
sDelete.start();
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
case 3:
{
printf("std::unique_ptr<char[]> buf((char *)malloc(%zu));\n", sSize);
Elapsed sElapsed;
std::unique_ptr<char[]> buf((char *)malloc(sSize));
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf.get(), sSize);
sDelete.start();
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
case 4:
{
printf("char *buf = (char *)malloc(%zu);\n", sSize);
Elapsed sElapsed;
char *buf = (char *)malloc(sSize);
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf, sSize);
sDelete.start();
free(buf);
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
case 5:
{
printf("std::unique_ptr<char> buf(new char[%zu]);\n", sSize);
Elapsed sElapsed;
std::unique_ptr<char> buf(new char[sSize]);
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf.get(), sSize);
sDelete.start();
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
case 6:
{
printf("std::unique_ptr<char[]> buf(new char[%zu]());\n", sSize);
Elapsed sElapsed;
std::unique_ptr<char[]> buf(new char[sSize]());
printf("%ld usec to alloc buffer\n", sElapsed.getElapsedMicro());
loop(buf.get(), sSize);
sDelete.start();
}
printf("%ld usec to free buffer\n", sDelete.getElapsedMicro());
break;
default:
printf("unknown method\n");
break;
}
return 0;
}
结果:
仔细看看它花了多少次。
使用make_unique
大约需要100毫秒,而new[]
只需要42个用户。
test$ g++ -std=c++14 -Wall -Werror new.cpp -O3
test$ ./a.out 100000000 1
std::unique_ptr<char[]> buf(std::make_unique<char[]>(100000000));
64176 usec to alloc buffer
42887 usec to loop buffer
8683 usec to free buffer
test$ ./a.out 100000000 2
std::unique_ptr<char[]> buf(new char[100000000]);
41 usec to alloc buffer
90317 usec to loop buffer
8322 usec to free buffer
test$ ./a.out 100000000 3
std::unique_ptr<char[]> buf((char *)malloc(100000000));
38 usec to alloc buffer
89392 usec to loop buffer
8311 usec to free buffer
test$ ./a.out 100000000 4
char *buf = (char *)malloc(100000000);
44 usec to alloc buffer
89310 usec to loop buffer
8320 usec to free buffer
test$ ./a.out 100000000 5
std::unique_ptr<char> buf(new char[100000000]);
46 usec to alloc buffer
88960 usec to loop buffer
8315 usec to free buffer
test$ ./a.out 100000000 6
std::unique_ptr<char[]> buf(new char[100000000]());
65898 usec to alloc buffer
42891 usec to loop buffer
8689 usec to free buffer
test$ g++ --version
g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
以下两个陈述之间的区别是什么?
std::unique_ptr<char[]> buf(std::make_unique<char[]>(size));
std::unique_ptr<char[]> buf(new char[size]);
valgrind给了我一些线索:make_unique()
初始化内存而new
没有:
test$ valgrind ./a.out 100 1
==21357== Memcheck, a memory error detector
==21357== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21357== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21357== Command: ./a.out 100 1
==21357==
std::unique_ptr<char[]> buf(std::make_unique<char[]>(100));
3880 usec to alloc buffer
555 usec to looping buffer
2927 usec to free buffer
==21357==
==21357== HEAP SUMMARY:
==21357== in use at exit: 0 bytes in 0 blocks
==21357== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==21357==
==21357== All heap blocks were freed -- no leaks are possible
==21357==
==21357== For counts of detected and suppressed errors, rerun with: -v
==21357== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
test$ valgrind ./a.out 100 2
==21358== Memcheck, a memory error detector
==21358== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21358== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21358== Command: ./a.out 100 2
==21358==
std::unique_ptr<char[]> buf(new char[100]);
3224 usec to alloc buffer
==21358== Conditional jump or move depends on uninitialised value(s)
==21358== at 0x4008E4: loop(char*, unsigned long) (in /home1/irteam/shawn/test/a.out)
==21358== by 0x400AD9: main (in /home1/irteam/shawn/test/a.out)
==21358==
690 usec to looping buffer
2906 usec to free buffer
==21358==
==21358== HEAP SUMMARY:
==21358== in use at exit: 0 bytes in 0 blocks
==21358== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==21358==
==21358== All heap blocks were freed -- no leaks are possible
==21358==
==21358== For counts of detected and suppressed errors, rerun with: -v
==21358== Use --track-origins=yes to see where uninitialised values come from
==21358== ERROR SUMMARY: 100 errors from 1 contexts (suppressed: 6 from 6)
test$ valgrind ./a.out 100 6
==7968== Memcheck, a memory error detector
==7968== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==7968== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==7968== Command: ./a.out 100 6
==7968==
std::unique_ptr<char[]> buf(new char[100]());
2509 usec to alloc buffer
2724 usec to looping buffer
788 usec to free buffer
==7968==
==7968== HEAP SUMMARY:
==7968== in use at exit: 0 bytes in 0 blocks
==7968== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==7968==
==7968== All heap blocks were freed -- no leaks are possible
==7968==
==7968== For counts of detected and suppressed errors, rerun with: -v
==7968== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
如果差异实际上是否初始化内存,我可以在c ++规范中找到它吗?
BTW,我已经阅读了Differences between std::make_unique and std::unique_ptr。
gettimeofday()
new
运算符获取()
并初始化缓冲区的第6种情况。答案 0 :(得分:1)
不是来自规范,但this std::make_unique
reference表示数组创建重载等同于
unique_ptr<T>(new typename std::remove_extent<T>::type[size]())
分配基本等同于
new T[size]()
根据this new
reference (construction section)表示每个元素都是value-initialized。
对于像char
这样的基本类型数组,这意味着每个元素都被初始化为零。
当你没有对数组进行值初始化时,数组元素将被默认构造,或者(对于基本类型)将不会被初始化。
没有初始化大型数组很快。初始化它,即使是全零,也不是那么快。哪个应该解释执行时间的差异。