C++11 has weak
, shared
, unique
, but is it meaningful to use instance generation using only new and delete in an environment where these can be used?
In C++11, is the method using only new, delete positioned as a method that should not be used?
Backward compatibility should not be considered
c++ c++11
Your answers have been updated to new
and unique
, so I'll explain what happened before update.
You may take it for granted, but
inti0;
When described as , the C-language compatible and uninitialized variable i0
is provided.This is
inti1=int();
inti2 { };
The default constructor runs and initializes with 0
.The same thing exists in new
int*j0 = new int;
int*j1 = new int();
int*j2 = new int{};
j0
remains uninitialized while j1
and j2
are initialized with 0
by the default constructor after memory is reserved.
And the main topic is
std::unique_ptr<int>k=std::make_unique<int>();
Therefore, the default constructor will be invoked, which will result in a forced initialization cost.
unique_ptr
can also be dynamically release()
.Therefore, the unique_ptr
destructor adds a test to see if the pointer it holds has been released.The execution time difference also includes that the hard-coded delete var;
statement omits this test.
In summary, the difference in initialization cost during execution?If you don't care about this difference, you should use unique
or shared
to prevent forgetting to deleteAlso, if initialization is dominant over runtime, you should review the structure rather than worry about the difference between new
and unique
.
In addition, if you use make_unique()
, you will need to call the constructor from make_unique()
, so you must make the constructor public
.
class Test {
Test() = default;
public:
static auto create() {
return std::make_unique<Test>();// error
}
};
Although malloc()
only secures memory and does not initialize, calloc()
clears zero.
I thought that one of the reasons for using new might be speed, so I did a verification.Below is the verification result.
#include<chrono>
# include <cstdlib>
# include <cstring>
# include <functional>
# include <iomanip>
# include <iostream>
# include <memory>
US>structure Test {
intv;
Test(intv):v(v){};
int f(inti)
{
v+=i;
return v;
}
};
auto benchmark(conststd::function<void(int)>&func,const int count=1)
{
auto start=std::chrono::high_resolution_clock::now();
for(inti=0;i<count;++i)func(i);
auto end=std::chrono::high_resolution_clock::now();
return std:chrono::duration_cast<std:chrono::nanoseconds>(end-start)
.count();
}
int main()
{
const int count = 100000;
intn;
// stack
n = 0;
auto stack_t=benchmark(
&n (inti){
Test t(i);
n + = t.f(i);
},
count);
std::cout<<"stack:"<<std::setw(12)<<stack_t<"ns,"<n
<<std::endl;
// malloc
n = 0;
auto malloc_t=benchmark(
&n (inti){
auto = static_cast<Test*>(std::malloc(sizeof(Test)));
t->v=i;
n + = t - > f(i);
std::free(t);
},
count);
std::cout<<"malloc:"<<std::setw(12)<<malloc_t<"ns,"<n
<<std::endl;
// new
n = 0;
auto new_t=benchmark(
&n (inti){
auto = new Test(i);
n + = t - > f(i);
delete;
},
count);
std::cout<<"new:"<<std::setw(12)<<new_t<"ns,"<n
<<std::endl;
// unique
n = 0;
auto unique_t=benchmark(
&n (inti){
auto = std::make_unique<Test>(i);
n + = t - > f(i);
},
count);
std::cout<<"unique:"<<std::setw(12)<unique_t<"ns,"<n
<<std::endl;
// shared
n = 0;
auto shared_t=benchmark(
&n (inti){
auto = std::make_shared<Test>(i);
n + = t - > f(i);
},
count);
std::cout<<"shared:"<<std::setw(12)<<shared_t<"ns,"<n
<<std::endl;
return 0;
}
*This code is for C++14
Compiled and executed the above code in macOS Apple LLVM version 8.1.0 (clang-802.0.38) with clang++-O0-std=c++14
(without optimization), the results were as follows:
stack: 2346911ns, 1409965408
malloc —7772341ns, 1409965408
new —8951401ns, 1409965408
unique —1086486862ns, 1409965408
shared —22686880ns, 1409965408
Unique_ptr and shared_ptr seem to be slower than new because they are wrapped.Furthermore, the slow shared_ptr may be due to reference counter processing.However, when I compiled it with clang++-O2-std=c++14
(with optimization), the results were as follows:
stack : 270138ns, 1409965408
malloc —306524ns, 1409965408
new —263298ns, 1409965408
unique —287971ns, 1409965408
shared —8967664ns, 1409965408
Except for shared_ptr, it is almost the same as stuck in the stack.With optimization, new and unique_ptr seem to be almost as fast as the stack.However, since the compiler and code depend on how much optimization is effective, I don't think it's possible to conclude that optimization can achieve the same speed.If you have evidence that unique_ptr may or may not be optimized at a speed equal to new, please provide us with information.
As for shared_ptr, perhaps because of the reference counter mechanism, it seems that it is being delayed.I didn't know if it could be optimized to the same speed as new.
Compiled with Homebrew GCC 6.3.0_1
#g++-6-O0-std=c++14
stack —2711000ns, 1409965408
malloc —9153000ns, 1409965408
new —13656000ns, 1409965408
unique —16941000ns, 1409965408
shared —33897000ns, 1409965408
# When g++-6-O2-std=c++14
stack —229000ns, 1409965408
malloc —251000ns, 1409965408
new: 7885000ns, 1409965408
unique —7101000ns, 1409965408
shared —8947000ns, 1409965408
Therefore, new and unique_ptr have almost the same results in optimization.
*I don't have the latest VC++ right now, so I would appreciate it if you could edit it and add it.
The conclusion from the validation is that if not optimized, the unique_ptr and shared_ptr will be slower than new, but the unique_ptr will be almost degrees faster and the shared_ptr may remain slower.However, it is difficult to conclude easily because the effectiveness of optimization depends on the compiler and code content.
The original verification code was a problem and should not be used as a reference.For more information, see Sayuri's answer.
C++11 has weak, shared, unique smart pointers, but is there any point in using instance generation using only new, delete in an environment where these can be used?
alpha comments, with std::make_unique<T>
added, C++14 and later should "avoid new/delete instance generation/destruction if smart pointers can meet the requirements."
In C++11, is the method using only new, delete positioned as a method that should not be used?
I don't think we should use new/delete unless we use the new operator (placement new, alignment specification).
Please also refer to the English SO Are new and delete still useful in C++14?
Basically, it should be unified with smart pointers.
However, make_shared is not easy to use in classes where the constructor is not public.
class Foo{
private:
Foo();
public:
static std::shared_ptr<Foo>create(){
return std::make_shared<Foo>();//compilation error
}
};
That's why
std::shared_ptr<Foo>(new Foo();;
I think you will be using new.However, many people dislike this and use make_shared using techniques.
© 2024 OneMinuteCode. All rights reserved.