/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/WeakPtr.h" using mozilla::SupportsWeakPtr; using mozilla::WeakPtr; static char IamB[] = "B"; static char IamC[] = "C"; static char IamD[] = "D"; class B : public SupportsWeakPtr { public: char const* whoAmI() const { return IamB; } }; // To have a class C support weak pointers, inherit from SupportsWeakPtr. class C : public SupportsWeakPtr { public: int mNum; C() : mNum(0) {} ~C() { // Setting mNum in the destructor allows us to test against use-after-free // below mNum = 0xDEAD; } char const* whoAmI() const { return IamC; } void act() {} bool isConst() { return false; } bool isConst() const { return true; } }; // Derived from a class that supports weakptr, but doesn't implement itself // To check upcast works as expected class D : public B { public: char const* whoAmI() const { return IamD; } }; bool isConst(C*) { return false; } bool isConst(const C*) { return true; } int main() { C* c1 = new C; MOZ_RELEASE_ASSERT(c1->mNum == 0); // Get weak pointers to c1. The first time, // a reference-counted WeakReference object is created that // can live beyond the lifetime of 'c1'. The WeakReference // object will be notified of 'c1's destruction. WeakPtr w1 = c1; // Test a weak pointer for validity before using it. MOZ_RELEASE_ASSERT(w1); MOZ_RELEASE_ASSERT(w1 == c1); w1->mNum = 1; w1->act(); // Test taking another WeakPtr to c1 WeakPtr w2 = c1; MOZ_RELEASE_ASSERT(w2); MOZ_RELEASE_ASSERT(w2 == c1); MOZ_RELEASE_ASSERT(w2 == w1); MOZ_RELEASE_ASSERT(w2->mNum == 1); // Test a WeakPtr WeakPtr w3const = c1; MOZ_RELEASE_ASSERT(w3const); MOZ_RELEASE_ASSERT(w3const == c1); MOZ_RELEASE_ASSERT(w3const == w1); MOZ_RELEASE_ASSERT(w3const == w2); MOZ_RELEASE_ASSERT(w3const->mNum == 1); // Test const-correctness of operator-> and operator T* MOZ_RELEASE_ASSERT(!w1->isConst()); MOZ_RELEASE_ASSERT(w3const->isConst()); MOZ_RELEASE_ASSERT(!isConst(w1)); MOZ_RELEASE_ASSERT(isConst(w3const)); // Test that when a WeakPtr is destroyed, it does not destroy the object that // it points to, and it does not affect other WeakPtrs pointing to the same // object (e.g. it does not destroy the WeakReference object). { WeakPtr w4local = c1; MOZ_RELEASE_ASSERT(w4local == c1); } // Now w4local has gone out of scope. If that had destroyed c1, then the // following would fail for sure (see C::~C()). MOZ_RELEASE_ASSERT(c1->mNum == 1); // Check that w4local going out of scope hasn't affected other WeakPtr's // pointing to c1 MOZ_RELEASE_ASSERT(w1 == c1); MOZ_RELEASE_ASSERT(w2 == c1); // Now construct another C object and test changing what object a WeakPtr // points to C* c2 = new C; c2->mNum = 2; MOZ_RELEASE_ASSERT(w2->mNum == 1); // w2 was pointing to c1 w2 = c2; MOZ_RELEASE_ASSERT(w2); MOZ_RELEASE_ASSERT(w2 == c2); MOZ_RELEASE_ASSERT(w2 != c1); MOZ_RELEASE_ASSERT(w2 != w1); MOZ_RELEASE_ASSERT(w2->mNum == 2); // Destroying the underlying object clears weak pointers to it. // It should not affect pointers that are not currently pointing to it. delete c1; MOZ_RELEASE_ASSERT(!w1, "Deleting an object should clear WeakPtr's to it."); MOZ_RELEASE_ASSERT(!w3const, "Deleting an object should clear WeakPtr's to it."); MOZ_RELEASE_ASSERT(w2, "Deleting an object should not clear WeakPtr that are not " "pointing to it."); delete c2; MOZ_RELEASE_ASSERT(!w2, "Deleting an object should clear WeakPtr's to it."); // Check that we correctly upcast to the base class supporting weakptr D* d = new D; WeakPtr db = d; // You should be able to use WeakPtr even if it's a base class which // implements SupportsWeakPtr. WeakPtr weakd = d; MOZ_RELEASE_ASSERT(db->whoAmI() == IamB); MOZ_RELEASE_ASSERT(weakd.get() == db.get()); delete d; MOZ_RELEASE_ASSERT(!db); MOZ_RELEASE_ASSERT(!weakd); }