문제

foo.h

#include <iostream>
#include <memory>

class Bar
{
public:
    Bar() {};
    ~Bar() {};
    void print() {
        std::cout << "hello";
    }
};

class Foo
{
public:
    Foo(); 
    ~Foo();
    void use() {
        pteste->print();
    }
private:
    std::unique_ptr<Bar> pteste;
};

#endif

main.cpp

#include <memory>
#include "foo.h"

int main(int argc, char *argv[]) 
{
    Foo s;
    s.use();

    return 0;
}

Why and how does it works "normally"?

Thanks

EDIT: I understand about the incomplete types, but what happens when I can use unique_ptr without using new and why works

EDIT2: Organized the code better for my question

도움이 되었습니까?

해결책

Short answer: It doesn't work.

This reference says that the default constructor of std::unique_ptr creates an empty unique pointer, meaning it has no associated object.

The reason why this code prints hello is because this statement

std::cout << "hello";

doesn't need anything of Bar. It could just as well be a static method. Maybe the compiler inlines the function and replaces s.use() with the std::cout-statement. But even if it does call the method, you won't notice any errors since it doesn't access the memory of Bar at all.

Make a slight change to your class and you will see what I mean:

class Bar
{
public:
    Bar() : data(10) {};
    ~Bar() {};
    void print() {
        std::cout << "hello, data is: " << data;
    }

    int data;
};

Now, print accesses invalid memory, because you never called new (or even better: make_unique). It may even work and print something to the console, but the output of data will be garbage. If you're lucky, the application will crash.

Another reason why it appears to work (thanks Stas):

std::unique_ptr defines operator->, which simply returns the contained pointer, but does not check if the pointer points to valid memory. So pteste-> won't throw an exception.

다른 팁

Yes, this code will "normally" print "hello" to console and it is not related to unique_ptr. You can replace std::unique_ptr<Bar> pteste with Bar* pteste in Bar and get the same result.

Consider how pteste->print() is called.

You can think about Bar::print() as a free function that take pointer to Bar object:

void print(Bar* this) {
    std::cout << "hello";
}

See, pointer passed to print(Bar*) is never touched, so you can theoretically pass whatever you want (null, garbage etc.) and it will print "hello" to console.

It works because

std::unique_ptr<Bar> pteste;

is a pointer declaration to the instance, it does not instantiate the pointer so it does not need to know at this point the details about Bar (e.g. ctor).

In the case of

Bar pteste

in order for pteste to be constructed it will need the know definition but since Bar is only forward declared it will give an error.

All pointers are implemented the same way. Even though you have pointers to different types, all are the size of an int usually. So the compiler does not need to know about the type of the pointee when it compiles your code. Now if you were to dereference that pointer that would be a different story. Even if you would initialize your unique_ptr it would need to know the type, since new needs to see the constructor.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top