So i just run a quick example and could use some help understanding what happend
I run the test with the Variable "RandomNumber" commented and the output was
Construct
Invoke
Destruct
So I run the test again but with the Variable "RandomNumber" uncommented and the output was
Construct
Destruct
Invoke
I tried that many times with the same result but i don't really understand why that Variable is changing the lifetime of the Tester...
The Test:
struct Container
{
template<typename T>
Container(T&& O) : Data((void*)std::addressof(O)) {}
private:
void* Data;
//std::weak_ptr<int> RandomNumber;
};
struct Tester
{
Tester() { std::cout << "Construct" << std::endl; }
~Tester() { std::cout << "Destruct" << std::endl; }
};
void TestFunction1(const std::vector<Container>& Data)
{
std::cout << "Invoke" << std::endl;
}
int main()
{
TestFunction1({ Tester() });
return 0;
}
After running the code multiple times on Windows 10, I have observed that it produces almost the same output whether weak_ptr<int> RandomNumber is commented or not:
Construct
Invoke
Destruct
This implies that output differs in systems as other online compilers have produced the same result as you. The most probable reason is the output is system/compiler dependent and the different optimizations the compiler does.
After testing on multiple configurations the result varies from system to system and compiler to compiler. Hence, it is difficult to predict what the outcome could be.
Related
Recently, I had the following
struct data {
std::vector<int> V;
};
data get_vector(int n)
{
std::vector<int> V(n,0);
return {V};
}
The problem with this code is that when the struct is created a copy occurs and the solution is instead to write return {std::move(V)}
Are there linter or code analyzer that would detect such spurious copy operations? Neither cppcheck, cpplint, nor clang-tidy can do it.
EDIT: Several points to make my question clearer:
I know that a copy operation occurred because I used compiler explorer and it shows a call to memcpy.
I could identify that a copy operations occurred by looking at the standard yes. But my initial wrong idea was that the compiler would optimize away this copy. I was wrong.
It is (likely) not a compiler problem since both clang and gcc produce code that produce a memcpy.
The memcpy may be cheap, but I cannot imagine circumstances where copying memory and deleting the original is cheaper than passing a pointer by a std::move.
The adding of the std::move is an elementary operation. I would imagine that a code analyzer would be able to suggest this correction.
I believe you have the correct observation but the wrong interpretation!
The copy will not occur by returning the value, because every normal clever compiler will use (N)RVO in this case. From C++17 this is mandatory, so you can't see any copy by returning a local generated vector from the function.
OK, lets play a bit with std::vector and what will happen during the construction or by filling it step by step.
First of all, lets generate a data type which makes every copy or move visible like this one:
template <typename DATA >
struct VisibleCopy
{
private:
DATA data;
public:
VisibleCopy( const DATA& data_ ): data{ data_ }
{
std::cout << "Construct " << data << std::endl;
}
VisibleCopy( const VisibleCopy& other ): data{ other.data }
{
std::cout << "Copy " << data << std::endl;
}
VisibleCopy( VisibleCopy&& other ) noexcept : data{ std::move(other.data) }
{
std::cout << "Move " << data << std::endl;
}
VisibleCopy& operator=( const VisibleCopy& other )
{
data = other.data;
std::cout << "copy assign " << data << std::endl;
}
VisibleCopy& operator=( VisibleCopy&& other ) noexcept
{
data = std::move( other.data );
std::cout << "move assign " << data << std::endl;
}
DATA Get() const { return data; }
};
And now lets start some experiments:
using T = std::vector< VisibleCopy<int> >;
T Get1()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec{ 1,2,3,4 };
std::cout << "End init" << std::endl;
return vec;
}
T Get2()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec(4,0);
std::cout << "End init" << std::endl;
return vec;
}
T Get3()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec;
vec.emplace_back(1);
vec.emplace_back(2);
vec.emplace_back(3);
vec.emplace_back(4);
std::cout << "End init" << std::endl;
return vec;
}
T Get4()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec;
vec.reserve(4);
vec.emplace_back(1);
vec.emplace_back(2);
vec.emplace_back(3);
vec.emplace_back(4);
std::cout << "End init" << std::endl;
return vec;
}
int main()
{
auto vec1 = Get1();
auto vec2 = Get2();
auto vec3 = Get3();
auto vec4 = Get4();
// All data as expected? Lets check:
for ( auto& el: vec1 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec2 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec3 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec4 ) { std::cout << el.Get() << std::endl; }
}
What can we observe:
Example 1)
We create a vector from a initializer list and maybe we expect that we will see 4 times construct and 4 moves. But we get 4 copies! That sounds a bit mysterious, but the reason is the implementation of initializer list! Simply it is not allowed to move from the list as the iterator from the list is a const T* which makes it impossible to move elements from it. A detailed answer on this topic can be found here: initializer_list and move semantics
Example 2)
In this case, we get a initial construction and 4 copies of the value. That is nothing special and is what we can expect.
Example 3)
Also here, we the the construction and some moves as expected. With my stl implementation the vector grows by factor 2 every time. So we see a first construct, another one and because the vector resizes from 1 to 2, we see the move of the first element. While adding the 3 one, we see a resize from 2 to 4 which needs a move of the first two elements. All as expected!
Example 4)
Now we reserve space and fill later. Now we have no copy and no move anymore!
In all cases, we do not see any move nor copy by returning the vector back to the caller at all! (N)RVO is taking place and no further action is required in this step!
Back to your question:
"How to find C++ spurious copy operations"
As seen above, you may introduce a proxy class in between for debugging purpose.
Making the copy-ctor private may not work in many cases, as you may have some wanted copies and some hidden ones. As above, only the code for example 4 will work with a private copy-ctor! And I can not answer the question, if the example 4 is the fastest one, as we fill peace by peace.
Sorry that I can not offer a general solution for finding "unwanted" copies here. Even if you dig your code for calls of memcpy, you will not find all as also memcpy will be optimized away and you see directly some assembler instructions doing the job without a call to your library memcpy function.
My hint is not to focus on such a minor problem. If you have real performance issues, take a profiler and measure. There are so many potential performance killers, that investing much time on spurious memcpy usage seems not such a worthwhile idea.
I know that a copy operation occurred because I used compiler explorer and it shows a call to memcpy.
Did you put your complete application into the compiler explorer, and did you enable optimizations? If not, then what you saw in the compiler explorer might or might not be what is happening with your application.
One issue with the code you posted is that you first create a std::vector, and then copy it into an instance of data. It would be better to initialize data with the vector:
data get_vector(int n)
{
return {std::vector<int> V(n,0)};
}
Also, if you just give the compiler explorer the definition of data and get_vector(), and nothing else, it has to expect the worse. If you actually give it some source code that uses get_vector(), then look at what assembly is generated for that source code. See this example for what the above modification plus actual usage plus compiler optimizations can cause the compiler to produce.
class test
{
int a;
static int cnt;
public:
test()
{
a=0;
cout <<++cnt;
}
test( int p)
{
a=p;
cout <<++cnt;
}
~test()
{
cout<<cnt--;
}
};
int test::cnt;
void main()
{
test ob,ob1(10);
ob = test();
test();
}
In this code snippet ob=test(); how ob can be assigned a function test.Test is a class and we are invoking it like a function.How can this be possible
Functions return void, objects, references or pointers to objects, that can generally be assigned to variables in your program. In this particular case, you are calling the test class object constructors and possibly encountering undefined behavior on the final call. I need to investigate further on the possible UB, the C++ standard has changed twice since I last read it, VS-2017 may not be the best oracle, and my C++ foo is little weak.
As far as I recall, there's more than one way to initialize an object in C++ and your instructor has obviously given you an assignment to learn this first hand.
test ob; // Invokes default constructor on test
test ob(); // Invokes default constructor on test.
test ob = test::test(); // Invokes default constructor on test.
It's always good to experiment with your code and get it to output usable diagnostics. I tweaked it a bit to get more organized output and force the app to wait on user input prior to exiting. You should also learn to use your debugger. You can learn a lot by simply stepping through your own code.
#include <iostream>
#include <cstdlib>
class test
{
int a;
static int cnt;
public:
test()
{
a = 0;
cnt++;
std::cout << cnt << std::endl;
}
test(int p)
{
a = p;
cnt++;
std::cout << cnt << std::endl;
}
~test()
{
std::cout << cnt << std::endl;
cnt--;
}
};
int test::cnt = 0;
int main(void)
{
{
test ob; // test::cnt is incremented, 1 is displayed on the console.
test ob1(10); // test::cnt is incremented, 2 is displayed on the console.
ob = test::test(); // test::cnt is incremented, 3 is displayed on the console.
// The following instantiates a temporary test object,
// the constructor is called, but test::cnt is not incremented on my system.
// Seems we might be in undefined behavior territory?
test::test();
}
system("pause");
}
Notice that I added an additional context to 'main()'. You can't rely on destructors outputting anything to the console after the end of 'main()' which is where your objects are destructed. Moving all the objects into the additional {} context, forces them to be constructed and destroyed therein, allowing us to a complete picture of what's going on at our console output.
The output on my Windows box for the above code is:
1
2
3
3
3
3
2
1
Press any key to continue . . .
I expected a count to 4 and then a count down from 4. That last call is definitely confusing me. If nobody chimes in with a definitive explanation, I'll look into it as soon as I can.
What I know about C++ is that the order of the constructions (and destructions) of global instances should not be assumed.
While I'm writing code with a global instance which uses std::cout in the constructor & destructor, I got a question.
std::cout is also a global instance of iostream. Is std::cout guaranteed to be initialized before any other global instances?
I wrote a simple test code and it works perfectly, but still I don't know why.
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
It prints
test::ctor
Hello world
test::dtor
Is there any possibility that the code doesn't run as expected?
The answer differs depending on if you're using C++03 or C++11.
In C++11, your code is guaranteed to work, but in C++03 it's unspecified; your only guarantee is that by the time main() is entered, the standard streams had been initialized. (That said, all mainstream implementations initialize them prior to running any dynamic initialization, making them fine to use.)
You can force initialization by constructing an std::ios_base::Init object, like so:
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
private:
std::ios_base::Init mInitializer;
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
Now when test constructs, it initializes mInitializer and guarantees the streams are ready to use.
C++11 fixed this slightly annoying behavior by acting as if every instance of #include <iostream> were followed by static std::ios_base::Init __unspecified_name__;. This automatically guarantees the streams are ready to use.
According to §27.3/2:
The objects [std::cin, std::cout, etc.] are constructed, and the
associations are established at some time prior to or during first
time an object of class ios_base::Init is constructed, and in any case
before the body of main begins execution.
Your question is about the order of construction of static objects. I believe that the language specification leaves it undefined.
GCC has the init_priority attribute to play with the order.
And I believe you should not worry that much in practice.
What I know about C++ is that the order of the constructions (and destructions) of global instances should not be assumed.
While I'm writing code with a global instance which uses std::cout in the constructor & destructor, I got a question.
std::cout is also a global instance of iostream. Is std::cout guaranteed to be initialized before any other global instances?
I wrote a simple test code and it works perfectly, but still I don't know why.
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
It prints
test::ctor
Hello world
test::dtor
Is there any possibility that the code doesn't run as expected?
The answer differs depending on if you're using C++03 or C++11.
In C++11, your code is guaranteed to work, but in C++03 it's unspecified; your only guarantee is that by the time main() is entered, the standard streams had been initialized. (That said, all mainstream implementations initialize them prior to running any dynamic initialization, making them fine to use.)
You can force initialization by constructing an std::ios_base::Init object, like so:
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
private:
std::ios_base::Init mInitializer;
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
Now when test constructs, it initializes mInitializer and guarantees the streams are ready to use.
C++11 fixed this slightly annoying behavior by acting as if every instance of #include <iostream> were followed by static std::ios_base::Init __unspecified_name__;. This automatically guarantees the streams are ready to use.
According to §27.3/2:
The objects [std::cin, std::cout, etc.] are constructed, and the
associations are established at some time prior to or during first
time an object of class ios_base::Init is constructed, and in any case
before the body of main begins execution.
Your question is about the order of construction of static objects. I believe that the language specification leaves it undefined.
GCC has the init_priority attribute to play with the order.
And I believe you should not worry that much in practice.
I've seen my colleague do the second snippet quite often. Why is this? I've tried adding print statements to track the ctors and dtors, but both seem identical.
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ct1);
std::vector<ClassTest> vecClass2;
vecClass2.push_back(ClassTest());
ClassTest& ct2 = vecClass2.back();
ct2.blah = blah // set some stuff
...
PS. I'm sorry if the title is misleading.
Edit:
Firstly, thank you all for your responses.
I've written a small application using std::move. The results are surprising to me perhaps because I've done something wrong ... would someone please explain why the "fast" path is performing significantly better.
#include <vector>
#include <string>
#include <boost/progress.hpp>
#include <iostream>
const std::size_t SIZE = 10*100*100*100;
//const std::size_t SIZE = 1;
const bool log = (SIZE == 1);
struct SomeType {
std::string who;
std::string bio;
SomeType() {
if (log) std::cout << "SomeType()" << std::endl;
}
SomeType(const SomeType& other) {
if (log) std::cout << "SomeType(const SomeType&)" << std::endl;
//this->who.swap(other.who);
//this->bio.swap(other.bio);
this->who = other.who;
this->bio = other.bio;
}
SomeType& operator=(SomeType& other) {
if (log) std::cout << "SomeType::operator=()" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
return *this;
}
~SomeType() {
if (log) std::cout << "~SomeType()" << std::endl;
}
void swap(SomeType& other) {
if (log) std::cout << "Swapping" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
}
// move semantics
SomeType(SomeType&& other) :
who(std::move(other.who))
, bio(std::move(other.bio)) {
if (log) std::cout << "SomeType(SomeType&&)" << std::endl;
}
SomeType& operator=(SomeType&& other) {
if (log) std::cout << "SomeType::operator=(SomeType&&)" << std::endl;
this->who = std::move(other.who);
this->bio = std::move(other.bio);
return *this;
}
};
int main(int argc, char** argv) {
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"slow\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
SomeType some;
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
//store.push_back(SomeType());
//store.back().swap(some);
store.push_back(std::move(some));
}
}
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"fast\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
store.push_back(SomeType());
SomeType& some = store.back();
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
}
}
return 0;
}
Output:
dev#ubuntu-10:~/Desktop/perf_test$ g++ -Wall -O3 push_back-test.cpp -std=c++0x
dev#ubuntu-10:~/Desktop/perf_test$ ./a.out
Timing "slow" path
3.36 s
Timing "fast" path
3.08 s
If the object is more expensive to copy after "set some stuff" than before, then the copy that happens when you insert the object into the vector will be less expensive if you insert the object before you "set some stuff" than after.
Really, though, since you should expect objects in a vector to be copied occasionally, this is probably not much of an optimization.
If we accept that your colleague's snippet is wise, because ClassTest is expensive to copy, I would prefer:
using std::swap;
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ClassTest());
swap(ct1, vecClass1.back());
I think it's clearer, and it may well be more exception-safe. The ... code presumably allocates resources and hence could throw an exception (or else what's making the fully-built ClassTest so expensive to copy?). So unless the vector really is local to the function, I don't think it's a good idea for it to be half-built while running that code.
Of course this is even more expensive if ClassTest only has the default swap implementation, but if ClassTest doesn't have an efficient swap, then it has no business being expensive to copy. So this trick perhaps should only be used with classes known to be friendly, rather than unknown template parameter types.
As Gene says, std::move is better anyway, if you have that C++0x feature.
If we're worried about ClassTest being expensive to copy, though, then relocating the vector is a terrifying prospect. So we should also either:
reserve enough space before adding anything,
use a deque instead of a vector.
The second version benefits from moving the temporary. The first version is copying the temporary vector. So the second one is potentially faster. The second version has also potentially smaller peak memory requirements, the first version creates two objects one temporary and one copy of it and only then deletes the temporary. You can improve the first version by explicitly moving the temporary:
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(std::move(ct1));
You should probably ask your collegue to know exactly why, but we can still take a guess. As James pointed out, it might be a tad more efficient if the object is more expensive to copy once constructed.
I see advantages in both versions.
I like your collegue's snippet because: although there are 2 objects in both cases, they only co-exist for a very short period of time in the second version. There is only one object available for editing: this avoids the potential error of editing ct1 after push_back.
I like your personal snippet because: invoking push_back to add a second object potentially invalidates the reference ct2, inducing a risk of undefined behavior. The first snippet does not present this risk.
They are identical (as far as I can see). Maybe he or she does that as an idiomatic custom.