이것이 null인지 확인
이것이 null 인지 확인하는 것이 합리적 입니까?
메서드가있는 클래스가 있다고 가정 해 보겠습니다. 해당 메서드 내에서을 확인 this == NULL
하고있는 경우 오류 코드를 반환합니다.
경우 이 널 (null)이 다음 수단이라는 객체가 삭제됩니다. 메서드가 아무것도 반환 할 수 있습니까?
업데이트 : 메서드가 여러 스레드에서 호출 될 수 있으며 다른 스레드가 메서드 내에있는 동안 개체가 삭제 될 수 있음을 언급하는 것을 잊었습니다.
this == null을 확인하는 것이 합리적입니까? 코드 리뷰를하는 동안 이것을 발견했습니다.
표준 C ++에서는 null 포인터에 대한 호출이 이미 정의되지 않은 동작이므로 이러한 검사에 의존하는 모든 코드는 표준이 아닙니다 (검사가 실행될 것이라는 보장도 없음).
이것은 비가 상 기능에도 적용됩니다.
this==0
그러나 일부 구현에서는을 허용 하고 결과적으로 해당 구현을 위해 특별히 작성된 라이브러리는 때때로이를 해킹으로 사용합니다. 이러한 쌍의 좋은 예는 VC ++ 및 MFC입니다. 정확한 코드 if (this == NULL)
는 기억 나지 않지만 어딘가에서 MFC 소스 코드에서 검사를 본 것을 분명히 기억 합니다.
과거의 어느 시점에서 this==0
호출자의 실수 로 인해이 코드가 충돌했기 때문에 디버깅 보조 도구로도있을 수 있습니다 . 따라서 향후 인스턴스를 포착하기 위해 검사가 삽입되었습니다. 하지만 그러한 경우에는 어설 션이 더 의미가 있습니다.
이 == null이면 개체가 삭제되었음을 의미합니다.
아니, 그런 의미는 아닙니다. 이는 메소드가 널 포인터 또는 널 포인터에서 얻은 참조에서 호출되었음을 의미합니다 (이러한 참조를 얻는 것은 이미 UB입니다). 이는와 관련이 없으며 delete
이러한 유형의 객체가 존재하지 않아도됩니다.
스레드에 대한 귀하의 메모는 걱정 스럽습니다. 충돌로 이어질 수있는 경쟁 조건이 있다고 확신합니다. 스레드가 개체를 삭제하고 포인터를 0으로 지정하면 다른 스레드가 해당 두 작업간에 해당 포인터를 통해 호출을 수행하여 this
null이 아니고 유효하지 않아 충돌이 발생할 수 있습니다. 마찬가지로, 다른 스레드가 객체를 생성하는 동안 스레드가 메서드를 호출하면 충돌이 발생할 수도 있습니다.
짧은 대답으로,이 변수에 대한 액세스를 동기화하려면 뮤텍스 또는 무언가를 사용해야합니다. 당신은 보장 할 필요가 this
없습니다 결코 null 또는 당신은 문제가있는 것입니다.
FWIW, 나는 (this != NULL)
결함이있는 코드를 잡는 데 도움이되는 주장에서 디버깅 검사를 사용했습니다 . 코드가 반드시 크래시없이 너무 멀리 떨어졌을 것이 아니라 메모리 보호 기능이없는 소형 임베디드 시스템에서는 실제로이 주장이 도움이되었습니다.
메모리 보호 기능이있는 시스템에서 OS는 일반적으로 NULL this
포인터로 호출 될 경우 액세스 위반에 부딪 히 므로 어설 션 값이 적습니다 this != NULL
. 그러나 보호 된 시스템에서도 반드시 가치가없는 이유는 Pavel의 의견을 참조하십시오.
나는 이것이 오래되었다는 것을 알고 있지만 우리가 C ++ 11-17을 다루고 있으므로 누군가 람다를 언급해야 할 것 같습니다. 나중에 비동기 적으로 호출 될 람다로이를 캡처하면 해당 람다가 호출되기 전에 "this"객체가 파괴 될 수 있습니다.
즉, 별도의 스레드에서 실행되거나 일반적으로 비동기식으로 실행되는 시간이 많이 드는 함수에 콜백으로 전달
편집 : 명확하게 말하면, 질문은 "이것이 null인지 확인하는 것이 합리적입니까?"였습니다. 저는 단지 현대 C ++의 광범위한 사용과 함께 더 널리 퍼질 수있는 시나리오를 제공하고 있습니다.
Contrived example :이 코드는 완전히 실행 가능합니다. 안전하지 않은 동작을 보려면 안전 동작 호출을 주석 처리하고 안전하지 않은 동작 호출의 주석 처리를 제거하십시오.
#include <memory>
#include <functional>
#include <iostream>
#include <future>
class SomeAPI
{
public:
SomeAPI() = default;
void DoWork(std::function<void(int)> cb)
{
DoAsync(cb);
}
private:
void DoAsync(std::function<void(int)> cb)
{
std::cout << "SomeAPI about to do async work\n";
m_future = std::async(std::launch::async, [](auto cb)
{
std::cout << "Async thread sleeping 10 seconds (Doing work).\n";
std::this_thread::sleep_for(std::chrono::seconds{ 10 });
// Do a bunch of work and set a status indicating success or failure.
// Assume 0 is success.
int status = 0;
std::cout << "Executing callback.\n";
cb(status);
std::cout << "Callback Executed.\n";
}, cb);
};
std::future<void> m_future;
};
class SomeOtherClass
{
public:
void SetSuccess(int success) { m_success = success; }
private:
bool m_success = false;
};
class SomeClass : public std::enable_shared_from_this<SomeClass>
{
public:
SomeClass(SomeAPI* api)
: m_api(api)
{
}
void DoWorkUnsafe()
{
std::cout << "DoWorkUnsafe about to pass callback to async executer.\n";
// Call DoWork on the API.
// DoWork takes some time.
// When DoWork is finished, it calls the callback that we sent in.
m_api->DoWork([this](int status)
{
// Undefined behavior
m_value = 17;
// Crash
m_data->SetSuccess(true);
ReportSuccess();
});
}
void DoWorkSafe()
{
// Create a weak point from a shared pointer to this.
std::weak_ptr<SomeClass> this_ = shared_from_this();
std::cout << "DoWorkSafe about to pass callback to async executer.\n";
// Capture the weak pointer.
m_api->DoWork([this_](int status)
{
// Test the weak pointer.
if (auto sp = this_.lock())
{
std::cout << "Async work finished.\n";
// If its good, then we are still alive and safe to execute on this.
sp->m_value = 17;
sp->m_data->SetSuccess(true);
sp->ReportSuccess();
}
});
}
private:
void ReportSuccess()
{
// Tell everyone who cares that a thing has succeeded.
};
SomeAPI* m_api;
std::shared_ptr<SomeOtherClass> m_data = std::shared_ptr<SomeOtherClass>();
int m_value;
};
int main()
{
std::shared_ptr<SomeAPI> api = std::make_shared<SomeAPI>();
std::shared_ptr<SomeClass> someClass = std::make_shared<SomeClass>(api.get());
someClass->DoWorkSafe();
// Comment out the above line and uncomment the below line
// to see the unsafe behavior.
//someClass->DoWorkUnsafe();
std::cout << "Deleting someClass\n";
someClass.reset();
std::cout << "Main thread sleeping for 20 seconds.\n";
std::this_thread::sleep_for(std::chrono::seconds{ 20 });
return 0;
}
Your method will most likely (may vary between compilers) be able to run and also be able to return a value. As long as it does not access any instance variables. If it tries this it will crash.
As others pointed out you can not use this test to see if an object has been deleted. Even if you could, it would not work, because the object may be deleted by another thread just after the test but before you execute the next line after the test. Use Thread synchronization instead.
If this
is null there is a bug in your program, most likely in the design of your program.
I know this is a old question, however I thought I will share my experience with use of Lambda capture
#include <iostream>
#include <memory>
using std::unique_ptr;
using std::make_unique;
using std::cout;
using std::endl;
class foo {
public:
foo(int no) : no_(no) {
}
template <typename Lambda>
void lambda_func(Lambda&& l) {
cout << "No is " << no_ << endl;
l();
}
private:
int no_;
};
int main() {
auto f = std::make_unique<foo>(10);
f->lambda_func([f = std::move(f)] () mutable {
cout << "lambda ==> " << endl;
cout << "lambda <== " << endl;
});
return 0;
}
This code segment faults
$ g++ -std=c++14 uniqueptr.cpp
$ ./a.out
Segmentation fault (core dumped)
If I remove the std::cout
statement from lambda_func
The code runs to completion.
It seems like, this statement f->lambda_func([f = std::move(f)] () mutable {
processes lambda captures before member function is invoked.
I'd also add that it's usually better to avoid null or NULL. I think the standard is changing yet again here but for now 0 is really what you want to check for to be absolutely sure you're getting what you want.
This is just a pointer passed as the first argument to a function (which is exactly what makes it a method). So long as you're not talking about virtual methods and/or virtual inheritance, then yes, you can find yourself executing an instance method, with a null instance. As others said, you almost certainly won't get very far with that execution before problems arise, but robust coding should probably check for that situation, with an assert. At least, it makes sense when you suspect it could be occuring for some reason, but need to track down exactly which class / call stack it's occurring in.
참고URL : https://stackoverflow.com/questions/1844005/checking-if-this-is-null
'program tip' 카테고리의 다른 글
블레이드에서 Laravel .env 변수에 액세스 (0) | 2020.12.08 |
---|---|
Objective C 메시지 디스패치 메커니즘 (0) | 2020.12.08 |
쉘에서 배열의 길이를 찾는 방법은 무엇입니까? (0) | 2020.12.08 |
참조 DLL 파일이 배포 프로젝트로 bin에 복사되지 않아 오류가 발생합니다. (0) | 2020.12.08 |
Windows에서 Postgresql 구성 파일 'postgresql.conf'는 어디에 있습니까? (0) | 2020.12.08 |